Skip to content

Aurelia Conditional Rendering — If, Show, and Dynamic Content

DodaTech Updated 2026-06-28 5 min read

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

  1. Using if for frequently toggled content. Each toggle creates and destroys DOM. Use show for content that toggles rapidly.
  2. Using show for content that is rarely shown. Hidden elements still have bound properties and watchers. Use if for rarely displayed content.
  3. Complex ternary expressions. Long ternaries are hard to read. Extract the logic to a ViewMethod or computed getter.
  4. Nesting if and repeat incorrectly. Template controllers need proper nesting. Use <template> as a wrapper when needed.
  5. Not handling the empty state. Lists should always show an empty state when the collection has no items.

Practice Questions

  1. What is the difference between if.bind and show.bind?
  2. When should you use if versus show?
  3. How do you implement a switch/case pattern in Aurelia templates?
  4. How do you load different components based on a condition?
  5. Challenge: Create a multi-step form with 4 steps. Each step is a component. Use if.bind to 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

Does `if.bind` destroy child components?

Yes. When if becomes false, all child elements and components are destroyed.

Can I animate `if` and `show` transitions?

Yes. Use Aurelia's animation library or CSS transitions.

What is `view-cache` on `if`?

It caches the child view when hidden, avoiding recreation when shown again.

Can I use `else` with `if` in Aurelia?

Yes, in Aurelia 2. In Aurelia 1, chain multiple if blocks with inverse conditions.

How do I conditionally render in SVG?

Use if.bind inside SVG templates. It works the same as HTML.

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