UNPKG

32.8 kBMarkdownView Raw
1# Alpine.js
2
3![npm bundle size](https://img.shields.io/bundlephobia/minzip/alpinejs)
4![npm version](https://img.shields.io/npm/v/alpinejs)
5[![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true)](https://alpinejs.codewithhugo.com/chat/)
6
7Alpine.js offers you the reactive and declarative nature of big frameworks like Vue or React at a much lower cost.
8
9You get to keep your DOM, and sprinkle in behavior as you see fit.
10
11Think of it like [Tailwind](https://tailwindcss.com/) for JavaScript.
12
13> Note: This tool's syntax is almost entirely borrowed from [Vue](https://vuejs.org/) (and by extension [Angular](https://angularjs.org/)). I am forever grateful for the gift they are to the web.
14
15## Translated documentation
16
17| Language | Link for documentation |
18| --- | --- |
19| Arabic | [**التوثيق باللغة العربية**](./README.ar.md) |
20| Chinese Simplified | [**简体中文文档**](./README.zh-CN.md) |
21| Chinese Traditional | [**繁體中文說明文件**](./README.zh-TW.md) |
22| German | [**Dokumentation in Deutsch**](./README.de.md) |
23| Indonesian | [**Dokumentasi Bahasa Indonesia**](./README.id.md) |
24| Japanese | [**日本語ドキュメント**](./README.ja.md) |
25| Portuguese | [**Documentação em Português**](./README.pt.md) |
26| Russian | [**Документация на русском**](./README.ru.md) |
27| Spanish | [**Documentación en Español**](./README.es.md) |
28| Turkish | [**Türkçe Dokümantasyon**](./README.tr.md) |
29| Français | [**Documentation en Français**](./README.fr.md) |
30| Korean | [**한국어 문서**](./README.ko.md) |
31
32## Install
33
34**From CDN:** Add the following script to the end of your `<head>` section.
35```html
36<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>
37```
38
39That's it. It will initialize itself.
40
41For production environments, it's recommended to pin a specific version number in the link to avoid unexpected breakage from newer versions.
42For example, to use version `2.8.1` (latest):
43```html
44<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.8.1/dist/alpine.min.js" defer></script>
45```
46
47**From npm:** Install the package from npm.
48```js
49npm i alpinejs
50```
51
52Include it in your script.
53```js
54import 'alpinejs'
55```
56
57**For IE11 support** Use the following scripts instead.
58```html
59<script type="module" src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js"></script>
60<script nomodule src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine-ie11.min.js" defer></script>
61```
62
63The pattern above is the [module/nomodule pattern](https://philipwalton.com/articles/deploying-es2015-code-in-production-today/) that will result in the modern bundle automatically loaded on modern browsers, and the IE11 bundle loaded automatically on IE11 and other legacy browsers.
64
65## Use
66
67*Dropdown/Modal*
68```html
69<div x-data="{ open: false }">
70 <button @click="open = true">Open Dropdown</button>
71
72 <ul
73 x-show="open"
74 @click.away="open = false"
75 >
76 Dropdown Body
77 </ul>
78</div>
79```
80
81*Tabs*
82```html
83<div x-data="{ tab: 'foo' }">
84 <button :class="{ 'active': tab === 'foo' }" @click="tab = 'foo'">Foo</button>
85 <button :class="{ 'active': tab === 'bar' }" @click="tab = 'bar'">Bar</button>
86
87 <div x-show="tab === 'foo'">Tab Foo</div>
88 <div x-show="tab === 'bar'">Tab Bar</div>
89</div>
90```
91
92You can even use it for non-trivial things:
93*Pre-fetching a dropdown's HTML content on hover.*
94```html
95<div x-data="{ open: false }">
96 <button
97 @mouseenter.once="
98 fetch('/dropdown-partial.html')
99 .then(response => response.text())
100 .then(html => { $refs.dropdown.innerHTML = html })
101 "
102 @click="open = true"
103 >Show Dropdown</button>
104
105 <div x-ref="dropdown" x-show="open" @click.away="open = false">
106 Loading Spinner...
107 </div>
108</div>
109```
110
111## Learn
112
113There are 14 directives available to you:
114
115| Directive | Description |
116| --- | --- |
117| [`x-data`](#x-data) | Declares a new component scope. |
118| [`x-init`](#x-init) | Runs an expression when a component is initialized. |
119| [`x-show`](#x-show) | Toggles `display: none;` on the element depending on expression (true or false). |
120| [`x-bind`](#x-bind) | Sets the value of an attribute to the result of a JS expression. |
121| [`x-on`](#x-on) | Attaches an event listener to the element. Executes JS expression when emitted. |
122| [`x-model`](#x-model) | Adds "two-way data binding" to an element. Keeps input element in sync with component data. |
123| [`x-text`](#x-text) | Works similarly to `x-bind`, but will update the `innerText` of an element. |
124| [`x-html`](#x-html) | Works similarly to `x-bind`, but will update the `innerHTML` of an element. |
125| [`x-ref`](#x-ref) | Convenient way to retrieve raw DOM elements out of your component. |
126| [`x-if`](#x-if) | Remove an element completely from the DOM. Needs to be used on a `<template>` tag. |
127| [`x-for`](#x-for) | Create new DOM nodes for each item in an array. Needs to be used on a `<template>` tag. |
128| [`x-transition`](#x-transition) | Directives for applying classes to various stages of an element's transition. |
129| [`x-spread`](#x-spread) | Allows you to bind an object of Alpine directives to an element for better reusability. |
130| [`x-cloak`](#x-cloak) | This attribute is removed when Alpine initializes. Useful for hiding pre-initialized DOM. |
131
132And 6 magic properties:
133
134| Magic Properties | Description |
135| --- | --- |
136| [`$el`](#el) | Retrieve the root component DOM node. |
137| [`$refs`](#refs) | Retrieve DOM elements marked with `x-ref` inside the component. |
138| [`$event`](#event) | Retrieve the native browser "Event" object within an event listener. |
139| [`$dispatch`](#dispatch) | Create a `CustomEvent` and dispatch it using `.dispatchEvent()` internally. |
140| [`$nextTick`](#nexttick) | Execute a given expression AFTER Alpine has made its reactive DOM updates. |
141| [`$watch`](#watch) | Will fire a provided callback when a component property you "watched" gets changed. |
142
143
144## Sponsors
145
146<img width="33%" src="https://refactoringui.nyc3.cdn.digitaloceanspaces.com/tailwind-logo.svg" alt="Tailwind CSS">
147
148**Want your logo here? [DM on Twitter](https://twitter.com/calebporzio)**
149
150## Community Projects
151
152* [AlpineJS Weekly Newsletter](https://alpinejs.codewithhugo.com/newsletter/)
153* [Spruce (State Management)](https://github.com/ryangjchandler/spruce)
154* [Turbolinks Adapter](https://github.com/SimoTod/alpine-turbolinks-adapter)
155* [Alpine Magic Helpers](https://github.com/KevinBatdorf/alpine-magic-helpers)
156* [Awesome Alpine](https://github.com/ryangjchandler/awesome-alpine)
157
158### Directives
159
160---
161
162### `x-data`
163
164**Example:** `<div x-data="{ foo: 'bar' }">...</div>`
165
166**Structure:** `<div x-data="[object literal]">...</div>`
167
168`x-data` declares a new component scope. It tells the framework to initialize a new component with the following data object.
169
170Think of it like the `data` property of a Vue component.
171
172**Extract Component Logic**
173
174You can extract data (and behavior) into reusable functions:
175
176```html
177<div x-data="dropdown()">
178 <button x-on:click="open">Open</button>
179
180 <div x-show="isOpen()" x-on:click.away="close">
181 // Dropdown
182 </div>
183</div>
184
185<script>
186 function dropdown() {
187 return {
188 show: false,
189 open() { this.show = true },
190 close() { this.show = false },
191 isOpen() { return this.show === true },
192 }
193 }
194</script>
195```
196
197> **For bundler users**, note that Alpine.js accesses functions that are in the global scope (`window`), you'll need to explicitly assign your functions to `window` in order to use them with `x-data` for example `window.dropdown = function () {}` (this is because with Webpack, Rollup, Parcel etc. `function`'s you define will default to the module's scope not `window`).
198
199
200You can also mix-in multiple data objects using object destructuring:
201
202```html
203<div x-data="{...dropdown(), ...tabs()}">
204```
205
206---
207
208### `x-init`
209**Example:** `<div x-data="{ foo: 'bar' }" x-init="foo = 'baz'"></div>`
210
211**Structure:** `<div x-data="..." x-init="[expression]"></div>`
212
213`x-init` runs an expression when a component is initialized.
214
215If you wish to run code AFTER Alpine has made its initial updates to the DOM (something like a `mounted()` hook in VueJS), you can return a callback from `x-init`, and it will be run after:
216
217`x-init="() => { // we have access to the post-dom-initialization state here // }"`
218
219---
220
221### `x-show`
222**Example:** `<div x-show="open"></div>`
223
224**Structure:** `<div x-show="[expression]"></div>`
225
226`x-show` toggles the `display: none;` style on the element depending if the expression resolves to `true` or `false`.
227
228**x-show.transition**
229
230`x-show.transition` is a convenience API for making your `x-show`s more pleasant using CSS transitions.
231
232```html
233<div x-show.transition="open">
234 These contents will be transitioned in and out.
235</div>
236```
237
238| Directive | Description |
239| --- | --- |
240| `x-show.transition` | A simultaneous fade and scale. (opacity, scale: 0.95, timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), duration-in: 150ms, duration-out: 75ms)
241| `x-show.transition.in` | Only transition in. |
242| `x-show.transition.out` | Only transition out. |
243| `x-show.transition.opacity` | Only use the fade. |
244| `x-show.transition.scale` | Only use the scale. |
245| `x-show.transition.scale.75` | Customize the CSS scale transform `transform: scale(.75)`. |
246| `x-show.transition.duration.200ms` | Sets the "in" transition to 200ms. The out will be set to half that (100ms). |
247| `x-show.transition.origin.top.right` | Customize the CSS transform origin `transform-origin: top right`. |
248| `x-show.transition.in.duration.200ms.out.duration.50ms` | Different durations for "in" and "out". |
249
250> Note: All of these transition modifiers can be used in conjunction with each other. This is possible (although ridiculous lol): `x-show.transition.in.duration.100ms.origin.top.right.opacity.scale.85.out.duration.200ms.origin.bottom.left.opacity.scale.95`
251
252> Note: `x-show` will wait for any children to finish transitioning out. If you want to bypass this behavior, add the `.immediate` modifier:
253```html
254<div x-show.immediate="open">
255 <div x-show.transition="open">
256</div>
257```
258---
259
260### `x-bind`
261
262> Note: You are free to use the shorter ":" syntax: `:type="..."`.
263
264**Example:** `<input x-bind:type="inputType">`
265
266**Structure:** `<input x-bind:[attribute]="[expression]">`
267
268`x-bind` sets the value of an attribute to the result of a JavaScript expression. The expression has access to all the keys of the component's data object, and will update every-time its data is updated.
269
270> Note: attribute bindings ONLY update when their dependencies update. The framework is smart enough to observe data changes and detect which bindings care about them.
271
272**`x-bind` for class attributes**
273
274`x-bind` behaves a little differently when binding to the `class` attribute.
275
276For classes, you pass in an object whose keys are class names, and values are boolean expressions to determine if those class names are applied or not.
277
278For example:
279`<div x-bind:class="{ 'hidden': foo }"></div>`
280
281In this example, the "hidden" class will only be applied when the value of the `foo` data attribute is `true`.
282
283**`x-bind` for boolean attributes**
284
285`x-bind` supports boolean attributes in the same way as value attributes, using a variable as the condition or any JavaScript expression that resolves to `true` or `false`.
286
287For example:
288```html
289<!-- Given: -->
290<button x-bind:disabled="myVar">Click me</button>
291
292<!-- When myVar == true: -->
293<button disabled="disabled">Click me</button>
294
295<!-- When myVar == false: -->
296<button>Click me</button>
297```
298
299This will add or remove the `disabled` attribute when `myVar` is true or false respectively.
300
301Boolean attributes are supported as per the [HTML specification](https://html.spec.whatwg.org/multipage/indices.html#attributes-3:boolean-attribute), for example `disabled`, `readonly`, `required`, `checked`, `hidden`, `selected`, `open`, etc.
302
303> Note: If you need a false state to show for your attribute, such as `aria-*`, chain `.toString()` to the value while binding to the attribute. For example: `:aria-expanded="isOpen.toString()"` would persist whether `isOpen` was `true` or `false`.
304
305**`.camel` modifier**
306**Example:** `<svg x-bind:view-box.camel="viewBox">`
307
308The `camel` modifier will bind to the camel case equivalent of the attribute name. In the example above, the value of `viewBox` will be bound the `viewBox` attribute as opposed to the `view-box` attribute.
309
310---
311
312### `x-on`
313
314> Note: You are free to use the shorter "@" syntax: `@click="..."`.
315
316**Example:** `<button x-on:click="foo = 'bar'"></button>`
317
318**Structure:** `<button x-on:[event]="[expression]"></button>`
319
320`x-on` attaches an event listener to the element it's declared on. When that event is emitted, the JavaScript expression set as its value is executed. You can use `x-on` with any event available for the element you're adding the directive on, for a full list of events, see [the Event reference on MDN](https://developer.mozilla.org/en-US/docs/Web/Events) for a list of possible values.
321
322If any data is modified in the expression, other element attributes "bound" to this data, will be updated.
323
324> Note: You can also specify a JavaScript function name.
325
326**Example:** `<button x-on:click="myFunction"></button>`
327
328This is equivalent to: `<button x-on:click="myFunction($event)"></button>`
329
330**`keydown` modifiers**
331
332**Example:** `<input type="text" x-on:keydown.escape="open = false">`
333
334You can specify specific keys to listen for using keydown modifiers appended to the `x-on:keydown` directive. Note that the modifiers are kebab-cased versions of `Event.key` values.
335
336Examples: `enter`, `escape`, `arrow-up`, `arrow-down`
337
338> Note: You can also listen for system-modifier key combinations like: `x-on:keydown.cmd.enter="foo"`
339
340**`.away` modifier**
341
342**Example:** `<div x-on:click.away="showModal = false"></div>`
343
344When the `.away` modifier is present, the event handler will only be executed when the event originates from a source other than itself, or its children.
345
346This is useful for hiding dropdowns and modals when a user clicks away from them.
347
348**`.prevent` modifier**
349**Example:** `<input type="checkbox" x-on:click.prevent>`
350
351Adding `.prevent` to an event listener will call `preventDefault` on the triggered event. In the above example, this means the checkbox wouldn't actually get checked when a user clicks on it.
352
353**`.stop` modifier**
354**Example:** `<div x-on:click="foo = 'bar'"><button x-on:click.stop></button></div>`
355
356Adding `.stop` to an event listener will call `stopPropagation` on the triggered event. In the above example, this means the "click" event won't bubble from the button to the outer `<div>`. Or in other words, when a user clicks the button, `foo` won't be set to `'bar'`.
357
358**`.self` modifier**
359**Example:** `<div x-on:click.self="foo = 'bar'"><button></button></div>`
360
361Adding `.self` to an event listener will only trigger the handler if the `$event.target` is the element itself. In the above example, this means the "click" event that bubbles from the button to the outer `<div>` will **not** run the handler.
362
363**`.window` modifier**
364**Example:** `<div x-on:resize.window="isOpen = window.outerWidth > 768 ? false : open"></div>`
365
366Adding `.window` to an event listener will install the listener on the global window object instead of the DOM node on which it is declared. This is useful for when you want to modify component state when something changes with the window, like the resize event. In this example, when the window grows larger than 768 pixels wide, we will close the modal/dropdown, otherwise maintain the same state.
367
368>Note: You can also use the `.document` modifier to attach listeners to `document` instead of `window`
369
370**`.once` modifier**
371**Example:** `<button x-on:mouseenter.once="fetchSomething()"></button>`
372
373Adding the `.once` modifier to an event listener will ensure that the listener will only be handled once. This is useful for things you only want to do once, like fetching HTML partials and such.
374
375**`.passive` modifier**
376**Example:** `<button x-on:mousedown.passive="interactive = true"></button>`
377
378Adding the `.passive` modifier to an event listener will make the listener a passive one, which means `preventDefault()` will not work on any events being processed, this can help, for example with scroll performance on touch devices.
379
380**`.debounce` modifier**
381**Example:** `<input x-on:input.debounce="fetchSomething()">`
382
383The `debounce` modifier allows you to "debounce" an event handler. In other words, the event handler will NOT run until a certain amount of time has elapsed since the last event that fired. When the handler is ready to be called, the last handler call will execute.
384
385The default debounce "wait" time is 250 milliseconds.
386
387If you wish to customize this, you can specify a custom wait time like so:
388
389```
390<input x-on:input.debounce.750="fetchSomething()">
391<input x-on:input.debounce.750ms="fetchSomething()">
392```
393
394**`.camel` modifier**
395**Example:** `<input x-on:event-name.camel="doSomething()">`
396
397The `camel` modifier will attach an event listener for the camel case equivalent event name. In the example above, the expression will be evaluated when the `eventName` event is fired on the element.
398
399---
400
401### `x-model`
402**Example:** `<input type="text" x-model="foo">`
403
404**Structure:** `<input type="text" x-model="[data item]">`
405
406`x-model` adds "two-way data binding" to an element. In other words, the value of the input element will be kept in sync with the value of the data item of the component.
407
408> Note: `x-model` is smart enough to detect changes on text inputs, checkboxes, radio buttons, textareas, selects, and multiple selects. It should behave [how Vue would](https://vuejs.org/v2/guide/forms.html) in those scenarios.
409
410**`.number` modifier**
411**Example:** `<input x-model.number="age">`
412
413The `number` modifier will convert the input's value to a number. If the value cannot be parsed as a valid number, the original value is returned.
414
415**`.debounce` modifier**
416**Example:** `<input x-model.debounce="search">`
417
418The `debounce` modifier allows you to add a "debounce" to a value update. In other words, the event handler will NOT run until a certain amount of time has elapsed since the last event that fired. When the handler is ready to be called, the last handler call will execute.
419
420The default debounce "wait" time is 250 milliseconds.
421
422If you wish to customize this, you can specifiy a custom wait time like so:
423
424```
425<input x-model.debounce.750="search">
426<input x-model.debounce.750ms="search">
427```
428
429---
430
431### `x-text`
432**Example:** `<span x-text="foo"></span>`
433
434**Structure:** `<span x-text="[expression]"`
435
436`x-text` works similarly to `x-bind`, except instead of updating the value of an attribute, it will update the `innerText` of an element.
437
438---
439
440### `x-html`
441**Example:** `<span x-html="foo"></span>`
442
443**Structure:** `<span x-html="[expression]"`
444
445`x-html` works similarly to `x-bind`, except instead of updating the value of an attribute, it will update the `innerHTML` of an element.
446
447> :warning: **Only use on trusted content and never on user-provided content.** :warning:
448>
449> Dynamically rendering HTML from third parties can easily lead to [XSS](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) vulnerabilities.
450
451---
452
453### `x-ref`
454**Example:** `<div x-ref="foo"></div><button x-on:click="$refs.foo.innerText = 'bar'"></button>`
455
456**Structure:** `<div x-ref="[ref name]"></div><button x-on:click="$refs.[ref name].innerText = 'bar'"></button>`
457
458`x-ref` provides a convenient way to retrieve raw DOM elements out of your component. By setting an `x-ref` attribute on an element, you are making it available to all event handlers inside an object called `$refs`.
459
460This is a helpful alternative to setting ids and using `document.querySelector` all over the place.
461
462> Note: you can also bind dynamic values for x-ref: `<span :x-ref="item.id"></span>` if you need to.
463
464---
465
466### `x-if`
467**Example:** `<template x-if="true"><div>Some Element</div></template>`
468
469**Structure:** `<template x-if="[expression]"><div>Some Element</div></template>`
470
471For cases where `x-show` isn't sufficient (`x-show` sets an element to `display: none` if it's false), `x-if` can be used to actually remove an element completely from the DOM.
472
473It's important that `x-if` is used on a `<template></template>` tag because Alpine doesn't use a virtual DOM. This implementation allows Alpine to stay rugged and use the real DOM to work its magic.
474
475> Note: `x-if` must have a single root element inside the `<template></template>` tag.
476
477> Note: When using `template` in a `svg` tag, you need to add a [polyfill](https://github.com/alpinejs/alpine/issues/637#issuecomment-654856538) that should be run before Alpine.js is initialized.
478
479---
480
481### `x-for`
482**Example:**
483```html
484<template x-for="item in items" :key="item">
485 <div x-text="item"></div>
486</template>
487```
488
489> Note: the `:key` binding is optional, but HIGHLY recommended.
490
491`x-for` is available for cases when you want to create new DOM nodes for each item in an array. This should appear similar to `v-for` in Vue, with one exception of needing to exist on a `template` tag, and not a regular DOM element.
492
493If you want to access the current index of the iteration, use the following syntax:
494
495```html
496<template x-for="(item, index) in items" :key="index">
497 <!-- You can also reference "index" inside the iteration if you need. -->
498 <div x-text="index"></div>
499</template>
500```
501
502If you want to access the array object (collection) of the iteration, use the following syntax:
503
504```html
505<template x-for="(item, index, collection) in items" :key="index">
506 <div>
507 <!-- You can also reference "collection" inside the iteration if you need. -->
508 <!-- Current item. -->
509 <div x-text="item"></div>
510 <!-- Same as above. -->
511 <div x-text="collection[index]"></div>
512 <!-- Previous item. -->
513 <div x-text="collection[index - 1]"></div>
514 </div>
515</template>
516```
517
518> Note: `x-for` must have a single root element inside of the `<template></template>` tag.
519
520> Note: When using `template` in a `svg` tag, you need to add a [polyfill](https://github.com/alpinejs/alpine/issues/637#issuecomment-654856538) that should be run before Alpine.js is initialized.
521
522#### Nesting `x-for`s
523You can nest `x-for` loops, but you MUST wrap each loop in an element. For example:
524
525```html
526<template x-for="item in items">
527 <div>
528 <template x-for="subItem in item.subItems">
529 <div x-text="subItem"></div>
530 </template>
531 </div>
532</template>
533```
534
535#### Iterating over a range
536
537Alpine supports the `i in n` syntax, where `n` is an integer, allowing you to iterate over a fixed range of elements.
538
539```html
540<template x-for="i in 10">
541 <span x-text="i"></span>
542</template>
543```
544
545---
546
547### `x-transition`
548**Example:**
549```html
550<div
551 x-show="open"
552 x-transition:enter="transition ease-out duration-300"
553 x-transition:enter-start="opacity-0 transform scale-90"
554 x-transition:enter-end="opacity-100 transform scale-100"
555 x-transition:leave="transition ease-in duration-300"
556 x-transition:leave-start="opacity-100 transform scale-100"
557 x-transition:leave-end="opacity-0 transform scale-90"
558>...</div>
559```
560
561```html
562<template x-if="open">
563 <div
564 x-transition:enter="transition ease-out duration-300"
565 x-transition:enter-start="opacity-0 transform scale-90"
566 x-transition:enter-end="opacity-100 transform scale-100"
567 x-transition:leave="transition ease-in duration-300"
568 x-transition:leave-start="opacity-100 transform scale-100"
569 x-transition:leave-end="opacity-0 transform scale-90"
570 >...</div>
571</template>
572```
573
574> The example above uses classes from [Tailwind CSS](https://tailwindcss.com).
575
576Alpine offers 6 different transition directives for applying classes to various stages of an element's transition between "hidden" and "shown" states. These directives work both with `x-show` AND `x-if`.
577
578These behave exactly like VueJS's transition directives, except they have different, more sensible names:
579
580| Directive | Description |
581| --- | --- |
582| `:enter` | Applied during the entire entering phase. |
583| `:enter-start` | Added before element is inserted, removed one frame after element is inserted. |
584| `:enter-end` | Added one frame after element is inserted (at the same time `enter-start` is removed), removed when transition/animation finishes.
585| `:leave` | Applied during the entire leaving phase. |
586| `:leave-start` | Added immediately when a leaving transition is triggered, removed after one frame. |
587| `:leave-end` | Added one frame after a leaving transition is triggered (at the same time `leave-start` is removed), removed when the transition/animation finishes.
588
589---
590
591### `x-spread`
592**Example:**
593```html
594<div x-data="dropdown()">
595 <button x-spread="trigger">Open Dropdown</button>
596
597 <span x-spread="dialogue">Dropdown Contents</span>
598</div>
599
600<script>
601 function dropdown() {
602 return {
603 open: false,
604 trigger: {
605 ['@click']() {
606 this.open = true
607 },
608 },
609 dialogue: {
610 ['x-show']() {
611 return this.open
612 },
613 ['@click.away']() {
614 this.open = false
615 },
616 }
617 }
618 }
619</script>
620```
621
622`x-spread` allows you to extract an element's Alpine bindings into a reusable object.
623
624The object keys are the directives (Can be any directive including modifiers), and the values are callbacks to be evaluated by Alpine.
625
626> Note: There are a couple of caveats to x-spread:
627> - When the directive being "spread" is `x-for`, you should return a normal expression string from the callback. For example: `['x-for']() { return 'item in items' }`.
628> - `x-data` and `x-init` can't be used inside a "spread" object.
629
630---
631
632### `x-cloak`
633**Example:** `<div x-data="{}" x-cloak></div>`
634
635`x-cloak` attributes are removed from elements when Alpine initializes. This is useful for hiding pre-initialized DOM. It's typical to add the following global style for this to work:
636
637```html
638<style>
639 [x-cloak] {
640 display: none !important;
641 }
642</style>
643```
644
645### Magic Properties
646
647> With the exception of `$el`, magic properties are **not available within `x-data`** as the component isn't initialized yet.
648
649---
650
651### `$el`
652**Example:**
653```html
654<div x-data>
655 <button @click="$el.innerHTML = 'foo'">Replace me with "foo"</button>
656</div>
657```
658
659`$el` is a magic property that can be used to retrieve the root component DOM node.
660
661### `$refs`
662**Example:**
663```html
664<span x-ref="foo"></span>
665
666<button x-on:click="$refs.foo.innerText = 'bar'"></button>
667```
668
669`$refs` is a magic property that can be used to retrieve DOM elements marked with `x-ref` inside the component. This is useful when you need to manually manipulate DOM elements.
670
671---
672
673### `$event`
674**Example:**
675```html
676<input x-on:input="alert($event.target.value)">
677```
678
679`$event` is a magic property that can be used within an event listener to retrieve the native browser "Event" object.
680
681> Note: The $event property is only available in DOM expressions.
682
683If you need to access $event inside of a JavaScript function you can pass it in directly:
684
685`<button x-on:click="myFunction($event)"></button>`
686
687---
688
689### `$dispatch`
690**Example:**
691```html
692<div @custom-event="console.log($event.detail.foo)">
693 <button @click="$dispatch('custom-event', { foo: 'bar' })">
694 <!-- When clicked, will console.log "bar" -->
695</div>
696```
697
698**Note on Event Propagation**
699
700Notice that, because of [event bubbling](https://en.wikipedia.org/wiki/Event_bubbling), when you need to capture events dispatched from nodes that are under the same nesting hierarchy, you'll need to use the [`.window`](https://github.com/alpinejs/alpine#x-on) modifier:
701
702**Example:**
703
704```html
705<div x-data>
706 <span @custom-event="console.log($event.detail.foo)"></span>
707 <button @click="$dispatch('custom-event', { foo: 'bar' })">
708<div>
709```
710
711> This won't work because when `custom-event` is dispatched, it'll propagate to its common ancestor, the `div`.
712
713**Dispatching to Components**
714
715You can also take advantage of the previous technique to make your components talk to each other:
716
717**Example:**
718
719```html
720<div x-data @custom-event.window="console.log($event.detail)"></div>
721
722<button x-data @click="$dispatch('custom-event', 'Hello World!')">
723<!-- When clicked, will console.log "Hello World!". -->
724```
725
726`$dispatch` is a shortcut for creating a `CustomEvent` and dispatching it using `.dispatchEvent()` internally. There are lots of good use cases for passing data around and between components using custom events. [Read here](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events) for more information on the underlying `CustomEvent` system in browsers.
727
728You will notice that any data passed as the second parameter to `$dispatch('some-event', { some: 'data' })`, becomes available through the new events "detail" property: `$event.detail.some`. Attaching custom event data to the `.detail` property is standard practice for `CustomEvent`s in browsers. [Read here](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) for more info.
729
730You can also use `$dispatch()` to trigger data updates for `x-model` bindings. For example:
731
732```html
733<div x-data="{ foo: 'bar' }">
734 <span x-model="foo">
735 <button @click="$dispatch('input', 'baz')">
736 <!-- After the button is clicked, `x-model` will catch the bubbling "input" event, and update foo to "baz". -->
737 </span>
738</div>
739```
740
741> Note: The $dispatch property is only available in DOM expressions.
742
743If you need to access $dispatch inside of a JavaScript function you can pass it in directly:
744
745`<button x-on:click="myFunction($dispatch)"></button>`
746
747---
748
749### `$nextTick`
750**Example:**
751```html
752<div x-data="{ fruit: 'apple' }">
753 <button
754 x-on:click="
755 fruit = 'pear';
756 $nextTick(() => { console.log($event.target.innerText) });
757 "
758 x-text="fruit"
759 ></button>
760</div>
761```
762
763`$nextTick` is a magic property that allows you to only execute a given expression AFTER Alpine has made its reactive DOM updates. This is useful for times you want to interact with the DOM state AFTER it's reflected any data updates you've made.
764
765---
766
767### `$watch`
768**Example:**
769```html
770<div x-data="{ open: false }" x-init="$watch('open', value => console.log(value))">
771 <button @click="open = ! open">Toggle Open</button>
772</div>
773```
774
775You can "watch" a component property with the `$watch` magic method. In the above example, when the button is clicked and `open` is changed, the provided callback will fire and `console.log` the new value.
776
777## Security
778If you find a security vulnerability, please send an email to [calebporzio@gmail.com]().
779
780Alpine relies on a custom implementation using the `Function` object to evaluate its directives. Despite being more secure then `eval()`, its use is prohibited in some environments, such as Google Chrome App, using restrictive Content Security Policy (CSP).
781
782If you use Alpine in a website dealing with sensitive data and requiring [CSP](https://csp.withgoogle.com/docs/strict-csp.html), you need to include `unsafe-eval` in your policy. A robust policy correctly configured will help protecting your users when using personal or financial data.
783
784Since a policy applies to all scripts in your page, it's important that other external libraries included in the website are carefully reviewed to ensure that they are trustworthy and they won't introduce any Cross Site Scripting vulnerability either using the `eval()` function or manipulating the DOM to inject malicious code in your page.
785
786## V3 Roadmap
787* Move from `x-ref` to `ref` for Vue parity?
788* Add `Alpine.directive()`
789* Add `Alpine.component('foo', {...})` (With magic `__init()` method)
790* Dispatch Alpine events for "loaded", "transition-start", etc... ([#299](https://github.com/alpinejs/alpine/pull/299)) ?
791* Remove "object" (and array) syntax from `x-bind:class="{ 'foo': true }"` ([#236](https://github.com/alpinejs/alpine/pull/236) to add support for object syntax for the `style` attribute)
792* Improve `x-for` mutation reactivity ([#165](https://github.com/alpinejs/alpine/pull/165))
793* Add "deep watching" support in V3 ([#294](https://github.com/alpinejs/alpine/pull/294))
794* Add `$el` shortcut
795* Change `@click.away` to `@click.outside`?
796
797## License
798
799Copyright © 2019-2020 Caleb Porzio and contributors
800
801Licensed under the MIT license, see [LICENSE.md](LICENSE.md) for details.