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 programmatically
11 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 component
21 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>