Description: The Alpine.directive() method allows you to extend Alpine's capabilities by creating your own custom x- attributes. This is incredibly powerful for encapsulating reusable DOM manipulation logic or for integrating third-party JavaScript libraries seamlessly into your Alpine components. Think of it as creating new verbs for Alpine's HTML vocabulary.
Alpine.directive('name', (el, { expression, modifiers }, { evaluate, effect, cleanup }) => { ... })This is the core function for defining a custom directive. Let's break down its components:
'name': A string representing the name of your directive. If you name it 'foo', you'll use it in HTML as x-foo.callbackFunction: This function is executed by Alpine when it encounters your directive on an element. It receives three main arguments:
el: The actual DOM element the directive is attached to. You can directly manipulate this element.{ expression, modifiers }: An object containing:
expression: A string representing the value passed to the directive. For x-foo="bar()", the expression is "bar()". For x-foo="myMessage", it's "myMessage".modifiers: An array of strings representing any modifiers appended to the directive name. For x-foo.debounce.500ms, modifiers would be ['debounce', '500ms'].{ evaluate, effect, cleanup }: An object containing utility functions provided by Alpine:
evaluate(expressionString): Evaluates a JavaScript expression string within the context of the current Alpine component. This is useful if your directive's expression is a piece of JavaScript code or a variable name whose value you need.effect(() => { ... }): This is crucial for reactivity. The callback function you pass to effect will be executed immediately. Alpine tracks any reactive properties (like those from x-data) accessed within this callback. If any of these properties change, Alpine will automatically re-run the callback. This ensures your directive updates when its underlying data changes.cleanup(() => { ... }): Registers a callback function that Alpine will execute when the element is removed from the DOM (e.g., due to an x-if or x-for). This is essential for cleaning up resources, such as event listeners, timers, or third-party library instances initialized by your directive, to prevent memory leaks.
// Example structure
Alpine.directive('highlight', (el, { expression, modifiers }, { evaluate, effect, cleanup }) => {
// 'expression' might be a color name like 'yellow' or a component property
// 'modifiers' could be ['text', 'bold'] for x-highlight.text.bold
effect(() => {
const value = evaluate(expression); // Get the current value of the expression
el.style.backgroundColor = value; // Apply the highlight
console.log(`Element ${el} highlighted with ${value}`);
if (modifiers.includes('text')) {
el.style.color = 'black'; // Example modifier usage
}
});
cleanup(() => {
// If we had set up any external listeners or objects, we'd clean them here.
// For simple style changes, often not needed, but good practice for complex directives.
console.log(`Cleanup for highlight directive on element ${el}`);
el.style.backgroundColor = ''; // Reset style
});
});
alpine:init EventThe alpine:init event is dispatched on the document object after Alpine.js has fully initialized itself but before it starts processing components and directives on the page. This is the designated and correct moment to register custom directives, global stores (Alpine.store()), and global helper functions (Alpine.magic()).
document.addEventListener('alpine:init', () => {
Alpine.directive('my-custom-directive', (el, ...) => {
// ... directive logic
});
Alpine.data('myComponent', () => ({ /* ... */ }));
Alpine.store('myStore', { /* ... */ });
});
alpine:init. If you try to register a directive after Alpine has already scanned the DOM and initialized components, Alpine won't recognize your new directive on elements that have already been processed. Python developers might be used to defining functions or classes anywhere and having them available, but with Alpine's lifecycle, this timing is critical.
el, expression, modifiers, and utilities like evaluate, effect, cleanup) is key:
Each part of the directive callback's signature serves a specific purpose.
effect for reactive expressions means your directive won't update when data changes. For example, if x-my-directive="message" and message changes, without effect, your directive won't re-run.evaluate when the expression is a variable name (e.g., x-my-directive="colorName" where colorName is 'blue' in x-data) will result in you getting the literal string "colorName" instead of its value "blue".cleanup for directives that set up external listeners or integrate with libraries that need explicit destruction can lead to memory leaks or unexpected behavior when elements are removed from the DOM.This example demonstrates a custom x-markdown directive. It takes a string of simple Markdown text and renders it as HTML. Edit the Markdown in the textarea to see the directive update the output in real-time, thanks to effect.