March 19, 2024
Using Alpine.js without setting directives
Tag directives are key to building Alpine.js components. However, Alpine is flexible enough that even if you don't have control over the HTML markup and cannot set directives directly on tags, you can still build Alpine components.
Quick intro to Alpine directives
An Alpine component must start with the x-data
directive. Its value can be an inline object:
1<div x-data="{ isOpen: false }">2</div>
Or you can use Alpine.data()
and have a seperate (reusable) Alpine component object
1<div x-data="myComponent"> 2</div> 3 4<script> 5 document.addEventListener('alpine:init', () => { 6 Alpine.data('myComponent', () => ({ 7 isOpen: false 8 })) 9 })10</script>
You can use inline directives:
1<div x-data="{ isOpen: false }">2 <button type="button" x-on:click="isOpen = !isOpen">Toggle</button>3 4 <div x-show="isOpen">5 <!-- -->6 </div>7</div>
Or encapsulate directives with x-bind
:
1<div x-data="myComponent"> 2 <button type="button" x-bind="btn">Toggle</button> 3 4 <div x-bind="content"> 5 <!-- --> 6 </div> 7</div> 8 9<script>10 document.addEventListener('alpine:init', () => {11 Alpine.data('myComponent', () => ({12 isOpen: false,13 14 btn: {15 ['x-on:click']() {16 this.open = !this.open;17 }18 },19 20 content: {21 ['x-show']() {22 return this.open;23 }24 }25 }))26 })27</script>
The directiveless approach
When you don't have control over the HTML markup, you can programmatically set the directives.
While you can programmatically set all the directives with element.setAttribute()
, it's probably not the cleanest or most maintainable approach especially for more complex components.
1element.setAttribute('x-on:click', 'open = !open')
Instead use x-bind
to encapsulate directives so you only have to programmatically set x-bind
on the elements you need.
1<div class="container"> 2 <button type="button">Toggle</button> 3 4 <div class="content"> 5 <!-- --> 6 </div> 7</div> 8 9<script>10 // set directives programmatically11 document.querySelector('.container')12 .setAttribute('x-data', 'myComponent');13 14 document.querySelector('.container button')15 .setAttribute('x-bind', 'btn');16 17 document.querySelector('.container .content')18 .setAttribute('x-bind', 'content');19 20 // the alpine component21 document.addEventListener('alpine:init', () => {22 Alpine.data('myComponent', () => ({23 isOpen: false,24 25 btn: {26 ['x-on:click']() {27 this.open = !this.open;28 }29 },30 31 content: {32 ['x-show']() {33 return this.open;34 }35 }36 }))37 })38</script>