Aurelia Conditional Rendering — If, Show, and Dynamic Content
In this tutorial, you will learn about Aurelia Conditional Rendering. We cover key concepts, practical examples, and best practices to help you master this topic.
Aurelia provides if.bind for conditional DOM inclusion and show.bind for visibility toggling. Understanding when to use each affects performance and user experience. Additional patterns like switch/case and dynamic composition handle complex conditional rendering.
What You'll Learn
You will learn the difference between if and show, when to use each, conditional class and style binding, and dynamic component rendering.
Why It Matters
if.bind adds and removes DOM elements. show.bind toggles visibility. Using if for frequently toggled content causes repeated DOM creation. Using show for rarely shown content keeps hidden elements in memory. Choosing correctly improves performance.
Real-World Use
A tabbed interface uses if.bind for tab content (only rendered tab is in DOM). A dropdown uses show.bind because it opens and closes frequently. A modal uses if.bind because modals are opened infrequently and should not exist in DOM when closed.
flowchart LR
A[Conditional Rendering] --> B[if.bind]
A --> C[show.bind]
A --> D[Ternary]
A --> E[Compose]
B --> F[Add/Remove DOM]
C --> G[display:none]
D --> H[Inline expression]
E --> I[Dynamic component]
if.bind — Conditional DOM Inclusion
<template>
<!-- Remove element when condition is false -->
<div if.bind="isAuthenticated">
Welcome, ${user.name}!
</div>
<!-- if with else (Aurelia 2) -->
<div if.bind="isLoading">
<spinner-component></spinner-component>
</div>
<div else>
<data-table rows.bind="data"></data-table>
</div>
<!-- if inside repeat -->
<div repeat.for="item of items">
<span if.bind="item.isActive" class="badge">Active</span>
<span if.bind="!item.isActive" class="badge inactive">Inactive</span>
</div>
<!-- Cache view with if.bind -->
<div if.bind="showPanel" view-cache>
Expensive component (cached)
</div>
</template>
show.bind — Visibility Toggle
<template>
<!-- Toggle display:none — element stays in DOM -->
<div show.bind="isDropdownOpen" class="dropdown">
<ul>
<li>Option 1</li>
<li>Option 2</li>
</ul>
</div>
<!-- Frequently toggled content -->
<div class="accordion">
<button click.delegate="toggleSection(1)">
Section 1 ${isOpen(1) ? '-' : '+'}
</button>
<div show.bind="isOpen(1)" class="accordion-content">
Content for section 1
</div>
</div>
</template>
if vs show — When to Use Each
export class ComparisonDemo {
frequentToggle = true; // Use show — toggles often
infrequentAction = false; // Use if — shown rarely
expensiveComponent = false; // Use if — avoid DOM cost
userMenuOpen = false; // Use show — quick toggle
}
<template>
<!-- SHOW: toggles often, lightweight to hide -->
<div show.bind="frequentToggle">Frequently toggled</div>
<div show.bind="userMenuOpen">User menu dropdown</div>
<!-- IF: shown rarely, expensive to create -->
<div if.bind="infrequentAction">Rarely seen modal</div>
<div if.bind="expensiveComponent">Heavy chart component</div>
</template>
Ternary and Inline Conditionals
<template>
<!-- Ternary in interpolation -->
<span>${isComplete ? 'Done' : 'Pending'}</span>
<div class="${isActive ? 'active' : 'inactive'}">Status</div>
<!-- Ternary with complex values -->
<span>${status === 'critical' ? 'bg-red' : status === 'warning' ? 'bg-yellow' : 'bg-green'}</span>
<!-- Logical AND -->
<span if.bind="isAdmin && showAdminPanel">
Admin Panel
</span>
<div show.bind="user && user.isActive">
${user.name}
</div>
<!-- Logical OR -->
<p>${displayName || email || 'Unknown User'}</p>
</template>
Switch/Case Patterns
<template>
<!-- Multiple conditions — use if/else chain -->
<div if.bind="status === 'active'" class="status-active">
<i class="icon-check"></i> Active
</div>
<div if.bind="status === 'pending'" class="status-pending">
<i class="icon-clock"></i> Pending
</div>
<div if.bind="status === 'suspended'" class="status-suspended">
<i class="icon-block"></i> Suspended
</div>
<div if.bind="status === 'deleted'" class="status-deleted">
<i class="icon-trash"></i> Deleted
</div>
<div if.bind="!status" class="status-unknown">
Unknown Status
</div>
</template>
Dynamic Component Composition
<template>
<!-- Dynamic component based on type -->
<compose view-model.bind="currentWidget.component"
model.bind="currentWidget.data">
</compose>
<!-- Conditional composition -->
<compose view-model.bind="isMobile ? './mobile-layout' : './desktop-layout'"
model.bind="pageData">
</compose>
</template>
export class Dashboard {
widgets = [
{ type: 'chart', component: './widgets/chart', data: { /* ... */ } },
{ type: 'table', component: './widgets/table', data: { /* ... */ } },
{ type: 'metric', component: './widgets/metric', data: { /* ... */ } }
];
currentWidget = this.widgets[0];
selectWidget(widget) {
this.currentWidget = widget;
}
}
Conditional Class and Style
<template>
<!-- Dynamic classes with ternary -->
<div class="btn ${variant} ${size} ${disabled ? 'disabled' : ''}">
${label}
</div>
<!-- Dynamic styles -->
<div style="background-color: ${bgColor}; height: ${height}px">
</div>
<!-- Conditional CSS class binding -->
<div class.bind="getClass()">Dynamic classes</div>
</template>
export class ConditionalDemo {
variant = 'primary';
size = 'md';
disabled = false;
bgColor = '#f0f0f0';
height = 100;
getClass() {
let classes = ['card'];
if (this.variant) classes.push(`card-${this.variant}`);
if (this.size) classes.push(`card-${this.size}`);
if (this.disabled) classes.push('card-disabled');
return classes.join(' ');
}
}
Loading States Pattern
<template>
<!-- Loading, error, empty, content states -->
<div if.bind="isLoading" class="loading">
<spinner></spinner>
<p>Loading content...</p>
</div>
<div if.bind="error" class="error">
<p>${error.message}</p>
<button click.delegate="retry()">Retry</button>
</div>
<div if.bind="!isLoading && !error && items.length === 0" class="empty">
<p>No items found.</p>
</div>
<div if.bind="!isLoading && !error && items.length > 0" class="content">
<div repeat.for="item of items">
${item.name}
</div>
</div>
</template>
Auth-Guarded Content
<template>
<!-- Role-based content visibility -->
<div if.bind="auth.isAdmin">
<h2>Admin Panel</h2>
<admin-controls></admin-controls>
</div>
<div if.bind="auth.isLoggedIn && !auth.isAdmin">
<p>User Dashboard</p>
</div>
<div if.bind="!auth.isLoggedIn">
<p>Please log in to continue.</p>
<login-form></login-form>
</div>
</template>
Common Mistakes
- Using
iffor frequently toggled content. Each toggle creates and destroys DOM. Useshowfor content that toggles rapidly. - Using
showfor content that is rarely shown. Hidden elements still have bound properties and watchers. Useiffor rarely displayed content. - Complex ternary expressions. Long ternaries are hard to read. Extract the logic to a ViewMethod or computed getter.
- Nesting
ifandrepeatincorrectly. Template controllers need proper nesting. Use<template>as a wrapper when needed. - Not handling the empty state. Lists should always show an empty state when the collection has no items.
Practice Questions
- What is the difference between
if.bindandshow.bind? - When should you use
ifversusshow? - How do you implement a switch/case pattern in Aurelia templates?
- How do you load different components based on a condition?
- Challenge: Create a multi-step form with 4 steps. Each step is a component. Use
if.bindto show only the current step. Add next/previous buttons. Validate the current step before advancing. Show a loading state while validation runs. Show error messages per field.
FAQ
Mini Project
Build a product listing page with: (1) Loading state with skeleton components. (2) Error state with retry button. (3) Empty state with illustration. (4) Content state with grid/list toggle. (5) Auth-guarded admin controls. (6) Dropdown filters that use show.bind. (7) Modal for product details that uses if.bind. Demonstrate when to use each pattern.
What's Next
Now that you understand conditional rendering, learn Aurelia List Rendering for collection displays. Then explore Aurelia Composition for dynamic component loading.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro