Skip to content

x:isolate Directive

The x:isolate directive isolates an HTML element and its child elements from binding operations. This allows child widgets to maintain their own independent binding context.

Basic Usage

Why Use It?

Problem: Binding Collision

Without x:isolate, the parent widget tries to process bindings in all child elements:

typescript
// WRONG - without using x:isolate
@Widget({
  selector: '.parent',
  template: `
    <div>
      <p x:text="parentData">Parent</p>
      
      <!-- Parent tries to process child's bindings too -->
      <div>
        <child-component></child-component>
      </div>
    </div>
  `
})
export class ParentWidget {
  @xproperty()
  parentData: string = 'Parent';
}

@Widget({
  selector: 'child-component',
  template: `
    <!-- These bindings are attempted to be processed by both parent and child -->
    <p x:text="childData">Child</p>
  `
})
export class ChildComponent {
  @xproperty()
  childData: string = 'Child';
}

Solution: Isolation with x:isolate

typescript
// CORRECT - using x:isolate
@Widget({
  selector: '.parent',
  template: `
    <div>
      <p x:text="parentData">Parent</p>
      
      <!-- Child widget is isolated -->
      <div x:isolate>
        <child-component></child-component>
      </div>
    </div>
  `
})
export class ParentWidget {
  @xproperty()
  parentData: string = 'Parent';
}

Isolation Scope

Element and Child Elements

x:isolate isolates the element and all child elements:

html
<div x:isolate>
  <!-- This element is isolated -->
  <p x:text="data1">Text 1</p>
  
  <!-- Child elements are also isolated -->
  <div>
    <span x:text="data2">Text 2</span>
    
    <!-- Nested child elements are also isolated -->
    <div>
      <p x:text="data3">Text 3</p>
    </div>
  </div>
</div>

Parent Widget Controls Isolation

The parent widget does not process any bindings inside the x:isolate area:

typescript
@Widget({
  selector: '.container',
  template: `
    <div>
      <!-- Processed by parent -->
      <p x:text="parentProp">Parent prop</p>
      
      <div x:isolate>
        <!-- SKIPPED by parent -->
        <p x:text="childProp">Child prop</p>
        <button x:on:click="childMethod">Click</button>
        <input x:model="childData">
      </div>
    </div>
  `
})

Multiple Widget Composition

Nested Widgets

typescript
@Widget({
  selector: '.app-layout',
  template: `
    <div class="layout">
      <header x:text="headerTitle">Header</header>
      
      <!-- Sidebar isolated -->
      <aside x:isolate>
        <sidebar-widget></sidebar-widget>
      </aside>
      
      <!-- Main content isolated -->
      <main x:isolate>
        <content-widget></content-widget>
      </main>
      
      <!-- Footer isolated -->
      <footer x:isolate>
        <footer-widget></footer-widget>
      </footer>
    </div>
  `
})
export class AppLayoutWidget {
  @xproperty()
  headerTitle: string = 'Application Title';
}

@Widget({
  selector: 'sidebar-widget',
  template: `
    <nav>
      <ul>
        <li x:on:click="navigate('home')">Home</li>
        <li x:on:click="navigate('settings')">Settings</li>
      </ul>
    </nav>
  `
})
export class SidebarWidget {
  navigate(page: string): void {
    console.log('Navigating to:', page);
  }
}

Widgets in Lists

typescript
@Widget({
  selector: '.product-list',
  template: `
    <div>
      <h2 x:text="title">Products</h2>
      
      <template x:for="product in products">
        <!-- Each product card isolated -->
        <div x:isolate>
          <product-card></product-card>
        </div>
      </template>
    </div>
  `
})
export class ProductListWidget {
  @xproperty()
  title: string = 'Product List';
  
  @xproperty()
  products = [
    { id: 1, name: 'Laptop' },
    { id: 2, name: 'Mouse' }
  ];
}

@Widget({
  selector: 'product-card',
  template: `
    <div class="card">
      <h3 x:text="productName">Product</h3>
      <button x:on:click="addToCart">Add to Cart</button>
    </div>
  `
})
export class ProductCardWidget {
  @xproperty()
  productName: string = '';
  
  addToCart(): void {
    console.log('Added to cart:', this.productName);
  }
}

Dynamic Content

Isolation with Conditional Rendering

typescript
@Widget({
  selector: '.conditional-container',
  template: `
    <div>
      <button x:on:click="toggleView">Toggle View</button>
      
      <div x:if="showWidgetA">
        <div x:isolate>
          <widget-a></widget-a>
        </div>
      </div>
      
      <div x:if="!showWidgetA">
        <div x:isolate>
          <widget-b></widget-b>
        </div>
      </div>
    </div>
  `
})
export class ConditionalContainerWidget {
  @xproperty()
  showWidgetA: boolean = true;
  
  toggleView(): void {
    this.showWidgetA = !this.showWidgetA;
  }
}

Usage with Shadow DOM

x:isolate is independent of shadow DOM usage:

typescript
@Widget({
  selector: '.shadow-parent',
  encapsulation: 'shadow', // Shadow DOM
  template: `
    <div>
      <p x:text="parentData">Parent</p>
      
      <!-- Isolation is needed even inside Shadow DOM -->
      <div x:isolate>
        <child-widget></child-widget>
      </div>
    </div>
  `
})
export class ShadowParentWidget {
  @xproperty()
  parentData: string = 'Parent with Shadow DOM';
}

Best Practices

1. Use x:isolate for Every Child Widget

typescript
// GOOD - Each child widget isolated
@Widget({
  selector: '.good-parent',
  template: `
    <div>
      <div x:isolate><widget-a></widget-a></div>
      <div x:isolate><widget-b></widget-b></div>
    </div>
  `
})

// BAD - No isolation
@Widget({
  selector: '.bad-parent',
  template: `
    <div>
      <widget-a></widget-a>
      <widget-b></widget-b>
    </div>
  `
})

2. Use x:isolate Wrapper Element

typescript
// GOOD - Wrapper element
@Widget({
  template: `
    <div>
      <div x:isolate>
        <child-widget></child-widget>
      </div>
    </div>
  `
})

// WORKS but without wrapper
@Widget({
  template: `
    <div>
      <child-widget x:isolate></child-widget>
    </div>
  `
})

3. Isolation in List Rendering

typescript
@Widget({
  template: `
    <template x:for="item in items">
      <div x:isolate>
        <item-widget></item-widget>
      </div>
    </template>
  `
})

Performance Notes

  • Processing Load: x:isolate reduces parent widget's binding operations
  • Independence: Each widget processes its own bindings
  • Collision Prevention: Prevents binding collisions
  • Memory: Each isolated widget holds its own context

Summary

  • Isolation: Isolates element and child elements from binding operations
  • Child widgets: Provides independent binding context
  • Collision prevention: Prevents parent-child binding collisions
  • Performance: Reduces unnecessary binding operations
  • Best practice: Use x:isolate for every child widget