Core Directives
Essential directives for creating reactive components and managing data flow.
x-data Component Initialization
Defines a reactive component with initial data. The root directive that makes elements reactive.
<div x-data="{ count: 0, message: 'Hello World' }">
<span x-text="message"></span>
<button x-on:click="count++">Count: <span x-text="count"></span></button>
</div>
x-text Text Content Binding
Sets the text content of an element. Automatically escapes HTML for security.
<div x-data="{ name: 'FyneJS', version: '1.0' }">
<h1 x-text="name"></h1>
<p x-text="`Version: ${version}`"></p>
</div>
\{{ ... }} Mustache Text Interpolation
Embed values inline without attributes. Escapes HTML by default.
<div x-data="{ first: 'Ada', last: 'Lovelace' }">
<p>Hello, \{{ first }} \{{ last }}!</p>
</div>
x-html HTML Content Binding
Sets the innerHTML of an element. Use with caution as it doesn't escape HTML.
<div x-data="{ content: '<strong>Bold text</strong>' }">
<div x-html="content"></div>
</div>
x-show Toggle Visibility
Shows or hides an element using CSS display property. Element remains in DOM.
<div x-data="{ visible: true }">
<button x-on:click="visible = !visible">Toggle</button>
<p x-show="visible">This text can be toggled!</p>
</div>
x-transition Transitions (enter/leave + end hooks)
Animate visibility changes with class-based phases or a simple toggle class list. Works with both
x-show and x-if.
Simple toggle form
<div x-data="{ open: false }">
<button x-on:click="open = !open">Toggle</button>
<div
x-show="open"
x-transition="opacity-0 transition-opacity duration-200"
class="p-4 bg-white rounded shadow"
>Fades in/out using your classes</div>
</div>
On show, the classes are added; on hide, they are removed. The framework waits for the computed CSS transition/animation duration (with delays) before finishing.
Configuration object form
You can pass an object with keys like duration,
easing, enter,
enterFrom, enterTo,
leave, leaveFrom,
leaveTo, and toggle.
See the TransitionConfig API reference for full details.
<div
x-show="open"
x-transition="{ duration: 300, easing: 'ease-out', enter: 'transition', enterFrom: 'opacity-0', enterTo: 'opacity-100' }"
>Dialog</div>
Granular phases (Tailwind-style)
<div
x-data="{ open: true }"
x-show="open"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-from="opacity-0 -translate-y-2"
x-transition:enter-to="opacity-100 translate-y-0"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-from="opacity-100 translate-y-0"
x-transition:leave-to="opacity-0 translate-y-2"
>Content</div>
Run code after transition ends
<div
x-data="{ open: true }"
x-show="open"
x-transition:enter="transition ease-out duration-500"
x-transition:enter-from="opacity-0 translate-x-full"
x-transition:enter-to="opacity-100 translate-x-0"
x-transition:enter.after="({ el, phase, config }) => console.log(phase, config.duration, el)"
>Slide-in panel</div>
Use .after (or .end) on
x-transition or any phase (e.g.,
x-transition:enter.after) to run an expression once the transition completes.
The handler receives: { el, phase, config } where config.duration is the
effective duration (ms) detected from CSS (including delays), and phase is enter or leave.
- Actual duration is computed from CSS transition/animation durations and delays; falls back only if none are defined.
- End callbacks do not run on cancellations—only on natural completion—to avoid duplicates.
- Works with
x-if: entering branches animate in; leaving branches animate out and are removed after completion. The original display is restored (includingdisplay: contentsfor template wrappers).
x-if x-else-if x-else Conditional Rendering
Conditionally render elements. Unlike x-show, these directives add/remove elements from DOM.
<div x-data="{ status: 'loading' }">
<div x-if="status === 'loading'">Loading...</div>
<div x-else-if="status === 'error'">Error occurred!</div>
<div x-else>Content loaded successfully</div>
</div>
x-for List Rendering
Renders a list of elements from arrays, objects, iterables, or numeric ranges. Supports complex iteration patterns with stable diffing via x-key.
<div x-data="{ items: ['Apple', 'Banana', 'Cherry'] }">
<ul>
<!-- Basic array loop with index -->
<li x-for="(item, index) in items" :key="index">
<span x-text="`${index + 1}. ${item}`"></span>
</li>
</ul>
</div>
<!-- Numeric range: iterate n times -->
<div x-data>
<template x-for="star in 5">
<span>⭐</span> <!-- Renders 5 stars -->
</template>
</div>
<!-- Object iteration: (value, key, index) -->
<div x-data="{ user: { name: 'Alice', role: 'Admin', status: 'Active' } }">
<template x-for="(value, key, index) in user">
<p><strong x-text="key"></strong>: <span x-text="value"></span></p>
</template>
</div>
<!-- Advanced: Using x-key for stable diffing with objects -->
<div x-data="{
users: [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
]
}">
<template x-for="user in users" x-key="user.id">
<div class="user-card">
<h3 x-text="user.name"></h3>
<p x-text="user.email"></p>
</div>
</template>
</div>
Supported Iterable Types
Arrays: item in items or (item, index) in items
Objects: (value, key) in obj or (value, key, index) in obj
Numbers: n in 5 iterates 5 times (n = 0, 1, 2, 3, 4)
Iterables: Map, Set, and other iterable objects
x-key for Stable Diffing
Use x-key on your template element to provide stable keys for efficient list updates. This prevents unnecessary DOM recreation when items are reordered or modified.
When working with objects, use unique properties like x-key="item.id" rather than array indices for better performance.
x-model Two-Way Data Binding
Creates two-way data binding for form inputs. Automatically syncs input values with data.
<div x-data="{ name: '', email: '', agree: false }">
<input x-model="name" placeholder="Your name">
<input x-model="email" type="email" placeholder="Your email">
<label><input x-model="agree" type="checkbox"> I agree</label>
<p>Name: <span x-text="name"></span></p>
</div>
x-init Initialization Code
Runs code when the component is initialized. Perfect for setup tasks.
<div x-data="{ time: '' }"
x-init="time = new Date().toLocaleTimeString()">
<p>Page loaded at: <span x-text="time"></span></p>
</div>
x-intersect:enter x-intersect:leave Intersection Observer
Trigger actions when elements enter or leave the viewport using the Intersection Observer API.
<div x-data="{ visible: false, count: 0 }">
<!-- Trigger when entering viewport -->
<div x-intersect:enter="visible = true; console.log('Element entered!')"
class="h-64 bg-blue-100 flex items-center justify-center">
<span x-text="visible ? 'I am visible!' : 'Scroll to see me'"></span>
</div>
<!-- Trigger when leaving viewport -->
<div x-intersect:leave="console.log('Element left viewport')"
class="h-32 bg-red-100">
Scroll past me!
</div>
<!-- With modifiers -->
<div x-intersect:enter.once.rootMargin-100px="count++"
class="h-48 bg-green-100">
<p>Triggered <span x-text="count"></span> times</p>
<p>(Only once, with 100px margin)</p>
</div>
</div>
Available Modifiers
.once - Trigger only once
.rootMargin-{pixels}px - Adjust detection area (e.g., .rootMargin-50px)
Use Cases
Perfect for lazy loading images, triggering animations on scroll, infinite scrolling, analytics tracking, and progressive disclosure of content.
Learn more: x-intersect Callback Context for details on the payload passed to your callbacks.
x-ref Element References
Create named references to DOM elements for direct access in your component logic via $refs.
<div x-data="{ focusInput() { $refs.myInput.focus(); } }">
<input x-ref="myInput" type="text" placeholder="Click button to focus me">
<button x-on:click="focusInput()">Focus Input</button>
<!-- Access ref in expressions -->
<p x-text="$refs.myInput?.value || 'Empty'"></p>
</div>
Multiple Refs & Shared Access
Multiple elements can share the same ref name—$refs.name returns an array when multiple elements match.
Refs are also accessible from child components, bubbling up the component tree until found.
Programmatic Refs
Use $ref(name) to get a ref, or $ref(name, value) to register any value (not just elements) as a ref.
Attribute Directives
Dynamic attribute binding for creating responsive and interactive elements.
x-bind:attr x:attr :attr Dynamic Attributes
Dynamically bind any HTML attribute. Supports multiple shorthand syntaxes for convenience.
<div x-data="{ disabled: false, url: 'https://fynejs.com' }">
<!-- Full syntax -->
<button x-bind:disabled="disabled">Button</button>
<!-- x: shorthand -->
<a x:href="url">Visit FyneJS</a>
<!-- : shorthand (shortest!) -->
<img :src="`/images/${imageFile}`" :alt="description">
<input :placeholder="dynamicPlaceholder" :value="inputValue">
</div>
Syntax Options
x-bind:attr="expr" - Full syntax
x:attr="expr" - Short syntax
:attr="expr" - Shortest syntax (Vue-style)
x-class Dynamic Classes
Conditionally apply CSS classes. Supports string, array, and object syntax.
<div x-data="{ active: true, type: 'primary' }">
<!-- Object syntax -->
<button x-class="{ 'bg-blue-500': active, 'bg-gray-500': !active }">
Toggle Button
</button>
<!-- String syntax -->
<div x-class="`btn btn-${type}`"></div>
</div>
x-style Dynamic Styles
Apply dynamic inline styles. Supports both object and string syntax.
<div x-data="{ width: 50, color: 'red' }">
<!-- Object syntax -->
<div x-style="{ width: width + '%', backgroundColor: color }">
Dynamic Box
</div>
<!-- String syntax -->
<div x-style="`color: ${color}; font-size: 16px`"></div>
</div>
Event Directives
Handle user interactions with powerful event binding and modifiers.
x-on:event Event Listeners
Attach event listeners to elements using the x-on directive or the convenient @ shorthand.
<div x-data="{ count: 0 }">
<!-- Long form syntax -->
<button x-on:click="count++">Increment</button>
<button x-on:click="count--">Decrement</button>
<!-- Shorthand @ syntax -->
<button @click="count++">Increment</button>
<button @click="count--">Decrement</button>
<!-- Form events -->
<input @input="console.log($event.target.value)">
<form @submit.prevent="handleSubmit()"></form>
<!-- Keyboard events -->
<input @keydown.enter="search()">
</div>
@ Shorthand Syntax
You can use @event as a shorthand for x-on:event. Both syntaxes work identically and support all the same modifiers.
Learn more: Event Callback Contexts for details on $event, $target variables and function arguments.
Event Modifiers
Powerful modifiers to control event behavior without writing additional JavaScript.
Execution Control
Control how events are handled
.prevent
Calls preventDefault() - stops default browser behavior
.stop
Calls stopPropagation() - prevents event bubbling
.self
Only trigger when event target is the element itself
.once
Remove event listener after first execution
.passive
Add passive event listener for better performance
.capture
Use capture phase instead of bubbling phase
.defer
Execute handler in next microtask
Key Modifiers
Filter events by specific keys
.enter
Enter key
.esc
Escape key
.space
Space key
.tab
Tab key
.up
Arrow Up
.down
Arrow Down
.left
Arrow Left
.right
Arrow Right
.home
Home key
.end
End key
.delete
Delete key
.backspace
Backspace
Combination Keys
Require modifier keys to be held
.ctrl
Require Ctrl key to be held down
.alt
Require Alt key to be held down
.shift
Require Shift key to be held down
.meta
Require Meta/Cmd key to be held down
💡 Combination Example:
x-on:keydown.ctrl.s.prevent="save()"
Triggers save() when Ctrl+S is pressed
Mouse & Touch
Mouse buttons and touch interactions
.left
Left mouse button only
.middle
Middle mouse button (scroll wheel)
.right
Right mouse button only
.outside
Click outside the element
.window
Bind the event on the window object
.single
Single touch point
.multi
Multiple touch points
Modifier Examples
<div x-data="{ message: '' }">
<!-- Prevent form submission -->
<form x-on:submit.prevent="handleSubmit()"></form>
<!-- Enter key to search -->
<input x-on:keydown.enter="search()" placeholder="Press Enter to search">
<!-- Ctrl+S to save -->
<div x-on:keydown.ctrl.s.prevent="save()">Press Ctrl+S to save</div>
<!-- Click outside to close -->
<div x-on:click.outside="isOpen = false">Modal content</div>
<!-- Stop event bubbling -->
<button x-on:click.stop="doNotBubble()">Isolated Click</button>
</div>
Component Directives
Advanced directives for building reusable components and managing component communication.
x-prop Reactive Props
Pass reactive properties to registered components, enabling parent-child component communication.
<!-- Parent component passing props -->
<div x-data="{ userName: 'John Doe', userRole: 'admin' }">
<component source="user-card" x-prop="{ name: userName, role: userRole }"></component>
</div>
XTool.registerComponent Reusable Components
Register reusable components using the XTool.registerComponent() method with HTML template literals.
// Component registration
XTool.registerComponent({
name: 'todo-item',
template: html`
<div x-data="{ completed: false }" class="todo-item">
<input x-model="completed" type="checkbox">
<span x-class="{ 'line-through': completed }" x-text="title"></span>
</div>
`
});
// Component usage in HTML
<div x-data="{ todos: ['Learn FyneJS', 'Build app'] }">
<div x-for="todo in todos">
<component source="todo-item" x-prop="{ title: todo }"></component>
</div>
</div>