Description: Create new x- attributes using Alpine.directive() to encapsulate reusable DOM manipulation logic or integrate with third-party libraries, extending Alpine's vocabulary. This allows you to make your Alpine components cleaner and more declarative by abstracting complex or repetitive DOM interactions into custom directives.
The core of creating custom directives is the Alpine.directive() method. It's typically registered within an alpine:init event listener to ensure Alpine knows about your directive before it starts processing the DOM.
The syntax is:
Alpine.directive('name', (el, { expression, modifiers }, { evaluate, effect, cleanup }) => {
// Directive logic here
});
'name': A string representing the name of your directive. If you register 'foo', you'll use it in your HTML as x-foo.
el: The native DOM element the directive is attached to. You can directly manipulate this element.
{ expression, modifiers }: An object containing:
expression: A string containing the value passed to the directive. For example, in x-foo="bar()", the expression is "bar()".modifiers: An array of strings representing any modifiers applied to the directive. For example, in x-foo.debounce.500ms, modifiers would be ['debounce', '500ms'].{ evaluate, effect, cleanup }: An object containing utility functions:
evaluate(expressionString): A function that evaluates an expression string within the current Alpine component's reactive scope. This is useful for getting data or calling methods from your component.effect(() => { ... }): A powerful utility. It runs the provided callback immediately and then re-runs it whenever any reactive Alpine properties accessed within that callback change. This is key for making directives that react to data updates.cleanup(() => { ... }): Registers a callback function that will be executed when the element is removed from the DOM, or when Alpine re-initializes on the element. Use this to clean up event listeners, timers, or any side effects your directive created to prevent memory leaks.alpine:init event:
This DOM event is fired once Alpine.js has fully initialized itself, discovered all components on the page, and is ready to go. It's the designated place to register custom directives, global stores (Alpine.store()), and global components (Alpine.data() that are not tied to a specific x-data initially but rather registered by name for later use).
document.addEventListener('alpine:init', () => {
Alpine.directive('my-directive', /* ... */);
// Other initializations like Alpine.store()
});
x-data, x-show, and your custom ones) during its initial startup. If you define a custom directive after Alpine has already processed the relevant part of the DOM, it won't be recognized. Always register directives inside a document.addEventListener('alpine:init', () => { ... }) callback. This ensures your directive is known to Alpine from the very beginning.
Alpine.directive provides several powerful tools (el, expression, modifiers, evaluate, effect, cleanup).
evaluate for dynamic expressions means you're just getting a static string.effect means your directive won't react to changes in Alpine data that its expression might depend on.cleanup can lead to memory leaks or unexpected behavior if event listeners or other resources aren't properly removed when the element is destroyed.effect and cleanup are Alpine's way of managing reactivity and resource lifecycle within directives.evaluate: The evaluate function executes the expression in the context of the Alpine component the directive is part of. This means it has access to that component's data and methods.
x-tooltip DirectiveHover over the elements below to see the custom x-tooltip directive in action. The directive dynamically creates and positions a tooltip.
The tooltip content for the button above will update as you type in the input field.
This tooltip uses modifiers to change its position.