Appearance
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