@alpinejs/docs 3.4.2-revision.2 → 3.5.2-revision.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpinejs/docs",
3
- "version": "3.4.2-revision.2",
3
+ "version": "3.5.2-revision.1",
4
4
  "description": "The documentation for Alpine",
5
5
  "author": "Caleb Porzio",
6
6
  "license": "MIT"
@@ -3,7 +3,7 @@ order: 4
3
3
  title: bind
4
4
  ---
5
5
 
6
- # `x-bind`
6
+ # x-bind
7
7
 
8
8
  `x-bind` allows you to set HTML attributes on elements based on the result of JavaScript expressions.
9
9
 
@@ -124,6 +124,14 @@ Just like the class objects, this syntax is entirely optional. Only use it if it
124
124
  <div style="color: red; display: flex;" ...>
125
125
  ```
126
126
 
127
+ Conditional inline styling is possible using expressions just like with x-bind:class. Short circuit operators can be used here as well by using a styles object as the second operand.
128
+ ```alpine
129
+ <div x-bind:style="true && { color: 'red' }">
130
+
131
+ <!-- Will render: -->
132
+ <div style="color: red;">
133
+ ```
134
+
127
135
  One advantage of this approach is being able to mix it in with existing styles on an element:
128
136
 
129
137
  ```alpine
@@ -3,7 +3,7 @@ order: 12
3
3
  title: cloak
4
4
  ---
5
5
 
6
- # `x-cloak`
6
+ # x-cloak
7
7
 
8
8
  Sometimes, when you're using AlpineJS for a part of your template, there is a "blip" where you might see your uninitialized template after the page loads, but before Alpine loads.
9
9
 
@@ -3,7 +3,7 @@ order: 1
3
3
  title: data
4
4
  ---
5
5
 
6
- # `x-data`
6
+ # x-data
7
7
 
8
8
  Everything in Alpine starts with the `x-data` directive.
9
9
 
@@ -3,7 +3,7 @@ order: 11
3
3
  title: effect
4
4
  ---
5
5
 
6
- # `x-effect`
6
+ # x-effect
7
7
 
8
8
  `x-effect` is a useful directive for re-evaluating an expression when one of its dependencies change. You can think of it as a watcher where you don't have to specify what property to watch, it will watch all properties used within it.
9
9
 
@@ -3,7 +3,7 @@ order: 8
3
3
  title: for
4
4
  ---
5
5
 
6
- # `x-for`
6
+ # x-for
7
7
 
8
8
  Alpine's `x-for` directive allows you to create DOM elements by iterating through a list. Here's a simple example of using it to create a list of colors based on an array.
9
9
 
@@ -3,7 +3,7 @@ order: 7
3
3
  title: html
4
4
  ---
5
5
 
6
- # `x-html`
6
+ # x-html
7
7
 
8
8
  `x-html` sets the "innerHTML" property of an element to the result of a given expression.
9
9
 
@@ -3,7 +3,7 @@ order: 16
3
3
  title: if
4
4
  ---
5
5
 
6
- # `x-if`
6
+ # x-if
7
7
 
8
8
  `x-if` is used for toggling elements on the page, similarly to `x-show`, however it completely adds and removes the element it's applied to rather than just changing its CSS display property to "none".
9
9
 
@@ -3,7 +3,7 @@ order: 11
3
3
  title: ignore
4
4
  ---
5
5
 
6
- # `x-ignore`
6
+ # x-ignore
7
7
 
8
8
  By default, Alpine will crawl and initialize the entire DOM tree of an element containing `x-init` or `x-data`.
9
9
 
@@ -3,7 +3,7 @@ order: 2
3
3
  title: init
4
4
  ---
5
5
 
6
- # `x-init`
6
+ # x-init
7
7
 
8
8
  The `x-init` directive allows you to hook into the initialization phase of any element in Alpine.
9
9
 
@@ -3,7 +3,7 @@ order: 7
3
3
  title: model
4
4
  ---
5
5
 
6
- # `x-model`
6
+ # x-model
7
7
 
8
8
  `x-model` allows you to bind the value of an input element to Alpine data.
9
9
 
@@ -336,3 +336,39 @@ The default throttle interval is 250 milliseconds, you can easily customize this
336
336
  ```alpine
337
337
  <input type="text" x-model.throttle.500ms="search">
338
338
  ```
339
+
340
+ <a name="programmatic access"></a>
341
+ ## Programmatic access
342
+
343
+ Alpine exposes under-the-hood utilities for getting and setting properties bound with `x-model`. This is useful for complex Alpine utilities that may want to override the default x-model behavior, or instances where you want to allow `x-model` on a non-input element.
344
+
345
+ You can access these utilities through a property called `_x_model` on the `x-model`ed element. `_x_model` has two methods to get and set the bound property:
346
+
347
+ * `el._x_model.get()` (returns the value of the bound property)
348
+ * `el._x_model.set()` (sets the value of the bound property)
349
+
350
+ ```alpine
351
+ <div x-data="{ username: 'calebporzio' }">
352
+ <div x-ref="div" x-model="username"></div>
353
+
354
+ <button @click="$refs.div._x_model.set('phantomatrix')">
355
+ Change username to: 'phantomatrix'
356
+ </button>
357
+
358
+ <span x-text="$refs.div._x_model.get()"></span>
359
+ </div>
360
+ ```
361
+
362
+ <!-- START_VERBATIM -->
363
+ <div class="demo">
364
+ <div x-data="{ username: 'calebporzio' }">
365
+ <div x-ref="div" x-model="username"></div>
366
+
367
+ <button @click="$refs.div._x_model.set('phantomatrix')">
368
+ Change username to: 'phantomatrix'
369
+ </button>
370
+
371
+ <span x-text="$refs.div._x_model.get()"></span>
372
+ </div>
373
+ </div>
374
+ <!-- END_VERBATIM -->
@@ -3,7 +3,7 @@ order: 5
3
3
  title: on
4
4
  ---
5
5
 
6
- # `x-on`
6
+ # x-on
7
7
 
8
8
  `x-on` allows you to easily run code on dispatched DOM events.
9
9
 
@@ -13,6 +13,8 @@ Here's an example of simple button that shows an alert when clicked.
13
13
  <button x-on:click="alert('Hello World!')">Say Hi</button>
14
14
  ```
15
15
 
16
+ > `x-on` can only listen for events with lower case names, as HTML attribtes are case-insensitive. Writing `x-on:CLICK` will listen for an event named `click`. If you need to listen for a custom event with a camelCase name, you can use the [`.camel` helper](#camel) to work around this limitation. Alternatively, you can use [`x-bind`](/directives/bind.md#bind-directives) to attach an `x-on` directive to an element in javascript code (where case will be preserved).
17
+
16
18
  <a name="shorthand-syntax"></a>
17
19
  ## Shorthand syntax
18
20
 
@@ -262,6 +264,19 @@ Sometimes you may want to listen for camelCased events such as `customEvent` in
262
264
 
263
265
  By adding `.camel` in the above example, Alpine is now listening for `customEvent` instead of `custom-event`.
264
266
 
267
+ <a name="dot"></a>
268
+ ### .dot
269
+
270
+ ```alpine
271
+ <div @custom-event.dot="handleCustomEvent">
272
+ ...
273
+ </div>
274
+ ```
275
+
276
+ Similar to the `.camelCase` modifier there may be situations where you want to listen for events that have dots in their name (like `custom.event`). Since dots within the event name are reserved by Alpine you need to write them with dashes and add the `.dot` modifier.
277
+
278
+ In the code example above `custom-event.dot` will correspond to the event name `custom.event`.
279
+
265
280
  <a name="passive"></a>
266
281
  ### .passive
267
282
 
@@ -3,7 +3,7 @@ order: 11
3
3
  title: ref
4
4
  ---
5
5
 
6
- # `x-ref`
6
+ # x-ref
7
7
 
8
8
  `x-ref` in combination with `$refs` is a useful utility for easily accessing DOM elements directly. It's most useful as a replacement for APIs like `getElementById` and `querySelector`.
9
9
 
@@ -3,7 +3,7 @@ order: 3
3
3
  title: show
4
4
  ---
5
5
 
6
- # `x-show`
6
+ # x-show
7
7
 
8
8
  `x-show` is one of the most useful and powerful directives in Alpine. It provides an expressive way to show and hide DOM elements.
9
9
 
@@ -3,7 +3,7 @@ order: 6
3
3
  title: text
4
4
  ---
5
5
 
6
- # `x-text`
6
+ # x-text
7
7
 
8
8
  `x-text` sets the text content of an element to the result of a given expression.
9
9
 
@@ -3,14 +3,14 @@ order: 10
3
3
  title: transition
4
4
  ---
5
5
 
6
- # `x-transition`
6
+ # x-transition
7
7
 
8
8
  Alpine provides a robust transitions utility out of the box. With a few `x-transition` directives, you can create smooth transitions between when an element is shown or hidden.
9
9
 
10
10
  There are two primary ways to handle transitions in Alpine:
11
11
 
12
- * [The Transition Helper]()
13
- * [Applying CSS Classes]()
12
+ * [The Transition Helper](#the-transition-helper)
13
+ * [Applying CSS Classes](#applying-css-classes)
14
14
 
15
15
  <a name="the-transition-helper"></a>
16
16
  ## The transition helper
@@ -33,7 +33,7 @@ This is by far the simplest way to get started with Alpine. Include the followin
33
33
  Notice the `@3.x.x` in the provided CDN link. This will pull the latest version of Alpine version 3. For stability in production, it's recommended that you hardcode the latest version in the CDN link.
34
34
 
35
35
  ```alpine
36
- <script defer src="https://unpkg.com/alpinejs@3.4.2/dist/cdn.min.js"></script>
36
+ <script defer src="https://unpkg.com/alpinejs@3.5.2/dist/cdn.min.js"></script>
37
37
  ```
38
38
 
39
39
  That's it! Alpine is now available for use inside your page.
@@ -70,7 +70,7 @@ The two main behavioral differences with this approach are:
70
70
  ## Alpine initialization
71
71
 
72
72
  <a name="alpine-initializing"></a>
73
- ### `Alpine.initializing`
73
+ ### `alpine:init`
74
74
 
75
75
  Ensuring a bit of code executes after Alpine is loaded, but BEFORE it initializes itself on the page is a necessary task.
76
76
 
@@ -85,7 +85,7 @@ document.addEventListener('alpine:init', () => {
85
85
  ```
86
86
 
87
87
  <a name="alpine-initialized"></a>
88
- ### `Alpine.initialized`
88
+ ### `alpine:initialized`
89
89
 
90
90
  Alpine also offers a hook that you can use to execute code After it's done initializing called `alpine:initialized`:
91
91
 
@@ -0,0 +1,45 @@
1
+ ---
2
+ order: 8
3
+ prefix: $
4
+ title: data
5
+ ---
6
+
7
+ # $data
8
+
9
+ `$data` is a magic property that gives you access to the current Alpine data scope (generally provided by `x-data`).
10
+
11
+ Most of the time, you can just access Alpine data within expressions directly. for example `x-data="{ message: 'Hello Caleb!' }"` will allow you to do things like `x-text="message"`.
12
+
13
+ However, sometimes it is helpful to have an actual object that encapsulates all scope that you can pass around to other functions:
14
+
15
+ ```alpine
16
+ <div x-data="{ greeting: 'Hello' }">
17
+ <div x-data="{ name: 'Caleb' }">
18
+ <button @click="sayHello($data)">Say Hello</button>
19
+ </div>
20
+ </div>
21
+
22
+ <script>
23
+ function sayHello({ greeting, name }) {
24
+ alert(greeting + ' ' + name + '!')
25
+ }
26
+ </script>
27
+ ```
28
+
29
+ <!-- START_VERBATIM -->
30
+ <div x-data="{ greeting: 'Hello' }" class="demo">
31
+ <div x-data="{ name: 'Caleb' }">
32
+ <button @click="sayHello($data)">Say Hello</button>
33
+ </div>
34
+ </div>
35
+
36
+ <script>
37
+ function sayHello({ greeting, name }) {
38
+ alert(greeting + ' ' + name + '!')
39
+ }
40
+ </script>
41
+ <!-- END_VERBATIM -->
42
+
43
+ Now when the button is pressed, the browser will alert `Hello Caleb!` because it was passed a data object that contained all the Alpine scope of the expression that called it (`@click="..."`).
44
+
45
+ Most applications won't need this magic property, but it can be very helpful for deeper, more complicated Alpine utilities.
@@ -3,7 +3,7 @@ order: 5
3
3
  title: dispatch
4
4
  ---
5
5
 
6
- # `$dispatch`
6
+ # $dispatch
7
7
 
8
8
  `$dispatch` is a helpful shortcut for dispatching browser events.
9
9
 
@@ -56,17 +56,17 @@ Notice that, because of [event bubbling](https://en.wikipedia.org/wiki/Event_bub
56
56
  <!-- 🚫 Won't work -->
57
57
  <div x-data>
58
58
  <span @notify="..."></span>
59
- <button @click="$dispatch('notify')">
60
- <div>
59
+ <button @click="$dispatch('notify')">Notify</button>
60
+ </div>
61
61
 
62
62
  <!-- ✅ Will work (because of .window) -->
63
63
  <div x-data>
64
64
  <span @notify.window="..."></span>
65
- <button @click="$dispatch('notify')">
66
- <div>
65
+ <button @click="$dispatch('notify')">Notify</button>
66
+ </div>
67
67
  ```
68
68
 
69
- > The first example won't work because when `custom-event` is dispatched, it'll propagate to its common ancestor, the `div`, not it's sibling, the `<span>`. The second example will work because the sibling is listening for `notify` at the `window` level, which the custom event will eventually bubble up to.
69
+ > The first example won't work because when `custom-event` is dispatched, it'll propagate to its common ancestor, the `div`, not its sibling, the `<span>`. The second example will work because the sibling is listening for `notify` at the `window` level, which the custom event will eventually bubble up to.
70
70
 
71
71
  <a name="dispatching-to-components"></a>
72
72
  ## Dispatching to other components
@@ -84,7 +84,7 @@ You can also take advantage of the previous technique to make your components ta
84
84
  </div>
85
85
 
86
86
  <div x-data>
87
- <button @click="$dispatch('set-title', 'Hello World!')">...</button>
87
+ <button @click="$dispatch('set-title', 'Hello World!')">Click me</button>
88
88
  </div>
89
89
  <!-- When clicked, the content of the h1 will set to "Hello World!". -->
90
90
  ```
@@ -97,10 +97,10 @@ You can also use `$dispatch()` to trigger data updates for `x-model` data bindin
97
97
  ```alpine
98
98
  <div x-data="{ title: 'Hello' }">
99
99
  <span x-model="title">
100
- <button @click="$dispatch('input', 'Hello World!')">
100
+ <button @click="$dispatch('input', 'Hello World!')">Click me</button>
101
101
  <!-- After the button is pressed, `x-model` will catch the bubbling "input" event, and update title. -->
102
102
  </span>
103
103
  </div>
104
104
  ```
105
105
 
106
- This opens up the door for making custom input components who's value can be set via `x-model`.
106
+ This opens up the door for making custom input components whose value can be set via `x-model`.
@@ -4,7 +4,7 @@ prefix: $
4
4
  title: el
5
5
  ---
6
6
 
7
- # `$el`
7
+ # $el
8
8
 
9
9
  `$el` is a magic property that can be used to retrieve the current DOM node.
10
10
 
@@ -4,7 +4,7 @@ prefix: $
4
4
  title: nextTick
5
5
  ---
6
6
 
7
- # `$nextTick`
7
+ # $nextTick
8
8
 
9
9
  `$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.
10
10
 
@@ -4,7 +4,7 @@ prefix: $
4
4
  title: refs
5
5
  ---
6
6
 
7
- # `$refs`
7
+ # $refs
8
8
 
9
9
  `$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. It's often used as a more succinct, scoped, alternative to `document.querySelector`.
10
10
 
@@ -4,7 +4,7 @@ prefix: $
4
4
  title: root
5
5
  ---
6
6
 
7
- # `$root`
7
+ # $root
8
8
 
9
9
  `$root` is a magic property that can be used to retrieve the root element of any Alpine component. In other words the closest element up the DOM tree that contains `x-data`.
10
10
 
@@ -4,7 +4,7 @@ prefix: $
4
4
  title: store
5
5
  ---
6
6
 
7
- # `$store`
7
+ # $store
8
8
 
9
9
  You can use `$store` to conveniently access global Alpine stores registered using [`Alpine.store(...)`](#). For example:
10
10
 
@@ -3,7 +3,7 @@ order: 4
3
3
  title: watch
4
4
  ---
5
5
 
6
- # `$watch`
6
+ # $watch
7
7
 
8
8
  You can "watch" a component property using the `$watch` magic method. For example:
9
9
 
@@ -104,3 +104,25 @@ Sometimes it's useful to evaluate an expression only the first time an element e
104
104
  ```alpine
105
105
  <div x-intersect.once="shown = true">...</div>
106
106
  ```
107
+
108
+ <a name="half"></a>
109
+ ### .half
110
+
111
+ Evaluates the expression once the intersection threshold exceeds `0.5`.
112
+
113
+ Useful for elements where it's important to show at least part of the element.
114
+
115
+ ```alpine
116
+ <div x-intersect.half="shown = true">...</div> // when `0.5` of the element is in the viewport
117
+ ```
118
+
119
+ <a name="full"></a>
120
+ ### .full
121
+
122
+ Evaluates the expression once the intersection threshold exceeds `0.99`.
123
+
124
+ Useful for elements where it's important to show the whole element.
125
+
126
+ ```alpine
127
+ <div x-intersect.full="shown = true">...</div> // when `0.99` of the element is in the viewport
128
+ ```
@@ -0,0 +1,251 @@
1
+ ---
2
+ order: 5
3
+ title: Morph
4
+ description: Morph an element into the provided HTML
5
+ graph_image: https://alpinejs.dev/social_morph.jpg
6
+ ---
7
+
8
+ # Morph Plugin
9
+
10
+ Alpine's Morph plugin allows you to "morph" an element on the page into the provided HTML template, all while preserving any browser or Alpine state within the "morphed" element.
11
+
12
+ This is useful for updating HTML from a server request without loosing Alpine's on-page state. A utility like this is at the core of full-stack frameworks like [Laravel Livewire](https://laravel-livewire.com/) and [Phoenix LiveView](https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript).
13
+
14
+ The best way to understand its purpose is with the following interactive visualization. Give it a try!
15
+
16
+ <!-- START_VERBATIM -->
17
+ <div x-data="{ slide: 1 }" class="border rounded">
18
+ <div>
19
+ <img :src="'/img/morphs/morph'+slide+'.png'">
20
+ </div>
21
+
22
+ <div class="flex w-full justify-between" style="padding-bottom: 1rem">
23
+ <div class="w-1/2 px-4">
24
+ <button @click="slide = (slide === 1) ? 13 : slide - 1" class="w-full bg-brand rounded-full text-center py-3 font-bold text-white">Previous</button>
25
+ </div>
26
+ <div class="w-1/2 px-4">
27
+ <button @click="slide = (slide % 13) + 1" class="w-full bg-brand rounded-full text-center py-3 font-bold text-white">Next</button>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ <!-- END_VERBATIM -->
32
+
33
+ <a name="installation"></a>
34
+ ## Installation
35
+
36
+ You can use this plugin by either including it from a `<script>` tag or installing it via NPM:
37
+
38
+ ### Via CDN
39
+
40
+ You can include the CDN build of this plugin as a `<script>` tag, just make sure to include it BEFORE Alpine's core JS file.
41
+
42
+ ```alpine
43
+ <!-- Alpine Plugins -->
44
+ <script defer src="https://unpkg.com/@alpinejs/morph@3.x.x/dist/cdn.min.js"></script>
45
+
46
+ <!-- Alpine Core -->
47
+ <script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
48
+ ```
49
+
50
+ ### Via NPM
51
+
52
+ You can install Morph from NPM for use inside your bundle like so:
53
+
54
+ ```shell
55
+ npm install @alpinejs/morph
56
+ ```
57
+
58
+ Then initialize it from your bundle:
59
+
60
+ ```js
61
+ import Alpine from 'alpinejs'
62
+ import morph from '@alpinejs/morph'
63
+
64
+ Alpine.plugin(morph)
65
+
66
+ ...
67
+ ```
68
+
69
+ <a name="alpine-morph"></a>
70
+ ## Alpine.morph()
71
+
72
+ The `Alpine.morph(el, newHtml)` allows you to imperatively morph a dom node based on passed in HTML. It accepts the following parameters:
73
+
74
+ | Parameter | Description |
75
+ | --- | --- |
76
+ | `el` | A DOM element on the page. |
77
+ | `newHtml` | A string of HTML to use as the template to morph the dom element into. |
78
+ | `options` (optional) | An options object used mainly for [injecting lifecycle hooks](#lifecycle-hooks). |
79
+
80
+ Here's an example of using `Alpine.morph()` to update an Alpine component with new HTML: (In real apps, this new HTML would likely be coming from the server)
81
+
82
+ ```alpine
83
+ <div x-data="{ message: 'Change me, then press the button!' }">
84
+ <input type="text" x-model="message">
85
+ <span x-text="message"></span>
86
+ </div>
87
+
88
+ <button>Run Morph</button>
89
+
90
+ <script>
91
+ document.querySelector('button').addEventListener('click', () => {
92
+ let el = document.querySelector('div')
93
+
94
+ Alpine.morph(el, `
95
+ <div x-data="{ message: 'Change me, then press the button!' }">
96
+ <h2>See how new elements have been added</h2>
97
+
98
+ <input type="text" x-model="message">
99
+ <span x-text="message"></span>
100
+
101
+ <h2>but the state of this component hasn't changed? Magical.</h2>
102
+ </div>
103
+ `)
104
+ })
105
+ </script>
106
+ ```
107
+
108
+ <!-- START_VERBATIM -->
109
+ <div class="demo">
110
+ <div x-data="{ message: 'Change me, then press the button!' }" id="morph-demo-1" class="space-y-2">
111
+ <input type="text" x-model="message" class="w-full">
112
+ <span x-text="message"></span>
113
+ </div>
114
+
115
+ <button id="morph-button-1" class="mt-4">Run Morph</button>
116
+ </div>
117
+
118
+ <script>
119
+ document.querySelector('#morph-button-1').addEventListener('click', () => {
120
+ let el = document.querySelector('#morph-demo-1')
121
+
122
+ Alpine.morph(el, `
123
+ <div x-data="{ message: 'Change me, then press the button!' }" id="morph-demo-1" class="space-y-2">
124
+ <h4>See how new elements have been added</h4>
125
+ <input type="text" x-model="message" class="w-full">
126
+ <span x-text="message"></span>
127
+ <h4>but the state of this component hasn't changed? Magical.</h4>
128
+ </div>
129
+ `)
130
+ })
131
+ </script>
132
+ <!-- END_VERBATIM -->
133
+
134
+ <a name="lifecycle-hooks"></a>
135
+ ### Lifecycle Hooks
136
+
137
+ The "Morph" plugin works by comparing two DOM trees, the live element, and the passed in HTML.
138
+
139
+ Morph walks both trees simultaneusly and compares each node and its children. If it finds differences, it "patches" (changes) the current DOM tree to match the passed in HTML's tree.
140
+
141
+ While the default algorithm is very capable, there are cases where you may want to hook into its lifecycle and observe or change its behavior as it's happening.
142
+
143
+ Before we jump into the available Lifecycle hooks themselves, let's first list out all the potential parameters they receive and explain what each one is:
144
+
145
+ | Parameter | Description |
146
+ | --- | --- |
147
+ | `el` | This is always the actual, current, DOM element on the page that will be "patched" (changed by Morph). |
148
+ | `toEl` | This is a "template element". It's a temporary element representing what the live `el` will be patched to. It will never actually live on the page and should only be used for reference purposes. |
149
+ | `childrenOnly()` | This is a function that can be called inside the hook to tell Morph to skip the current element and only "patch" its children. |
150
+ | `skip()` | A function that when called within the hook will "skip" comparing/patching itself and the children of the current element. |
151
+
152
+ Here are the available lifecycle hooks (passed in as the third parameter to `Alpine.morph(..., options)`):
153
+
154
+ | Option | Description |
155
+ | --- | --- |
156
+ | `updating(el, toEl, childrenOnly, skip)` | Called before patching the `el` with the comparison `toEl`. |
157
+ | `updated(el, toEl)` | Called after Morph has patched `el`. |
158
+ | `removing(el, skip)` | Called before Morph removes an element from the live DOM. |
159
+ | `removed(el)` | Called after Morph has removed an element from the live DOM. |
160
+ | `adding(el, sip)` | Called before adding a new element. |
161
+ | `added(el)` | Called after adding a new element to the live DOM tree. |
162
+ | `key(el)` | A re-usable function to determine how Morph "keys" elements in the tree before comparing/patching. [More on that here](#keys) |
163
+ | `lookahead` | A boolean value telling Morph to enable an extra feature in its algorithm that "looks ahead" to make sure a DOM element that's about to be removed should instead just be "moved" to a later sibling. |
164
+
165
+ Here is code of all these lifecycle hooks for a more concrete reference:
166
+
167
+ ```js
168
+ Alpine.morph(el, newHtml, {
169
+ updating(el, toEl, childrenOnly, skip) {
170
+ //
171
+ },
172
+
173
+ updated(el, toEl) {
174
+ //
175
+ },
176
+
177
+ removing(el, skip) {
178
+ //
179
+ },
180
+
181
+ removed(el) {
182
+ //
183
+ },
184
+
185
+ adding(el, skip) {
186
+ //
187
+ },
188
+
189
+ added(el) {
190
+ //
191
+ },
192
+
193
+ key(el) {
194
+ // By default Alpine uses the `key=""` HTML attribute.
195
+ return el.id
196
+ },
197
+
198
+ lookahead: true, // Default: false
199
+ })
200
+ ```
201
+
202
+ <a name="keys"></a>
203
+ ### Keys
204
+
205
+ Dom-diffing utilities like Morph try their best to accurately "morph" the original DOM into the new HTML. However, there are cases where it's impossible to determine if an element should be just changed, or replaced completely.
206
+
207
+ Because of this limitation, Morph has a "key" system that allows developers to "force" preserving certain elements rather than replacing them.
208
+
209
+ The most common use-case for them is a list of siblings within a loop. Below is an example of why keys are necessary sometimes:
210
+
211
+ ```html
212
+ <!-- "Live" Dom on the page: -->
213
+ <ul>
214
+ <li>Mark</li>
215
+ <li>Tom</li>
216
+ <li>Travis</li>
217
+ </ul>
218
+
219
+ <!-- New HTML to "morph to": -->
220
+ <ul>
221
+ <li>Travis</li>
222
+ <li>Mark</li>
223
+ <li>Tom</li>
224
+ </ul>
225
+ ```
226
+
227
+ Given the above situation, Morph has no way to know that the "Travis" node has been moved in the DOM tree. It just thinks that "Mark" has been changed to "Travis" and "Travis" changed to "Tom".
228
+
229
+ This is not what we actually want, we want Morph to preserve the original elements and instead of changing them, MOVE them within the `<ul>`.
230
+
231
+ By adding keys to each node, we can accomplish this like so:
232
+
233
+ ```html
234
+ <!-- "Live" Dom on the page: -->
235
+ <ul>
236
+ <li key="1">Mark</li>
237
+ <li key="2">Tom</li>
238
+ <li key="3">Travis</li>
239
+ </ul>
240
+
241
+ <!-- New HTML to "morph to": -->
242
+ <ul>
243
+ <li key="3">Travis</li>
244
+ <li key="1">Mark</li>
245
+ <li key="2">Tom</li>
246
+ </ul>
247
+ ```
248
+
249
+ Now that there are "keys" on the `<li>`s, Morph will match them in both trees and move them accordingly.
250
+
251
+ You can configure what Morph considers a "key" with the `key:` configutation option. [More on that here](#lifecycle-hooks)
@@ -194,3 +194,14 @@ Alpine.data('dropdown', function () {
194
194
  }
195
195
  })
196
196
  ```
197
+
198
+ <a name="using-alpine-persist-global"></a>
199
+ ## Using the Alpine.$persist global
200
+
201
+ `Alpine.$persist` is exposed globally so it can be used outside of `x-data` contexts. This is useful to persist data from other sources such as `Alpine.store`.
202
+
203
+ ```js
204
+ Alpine.store('darkMode', {
205
+ on: Alpine.$persist(true).as('darkMode_on')
206
+ });
207
+ ```
@@ -178,3 +178,76 @@ Here is nesting in action:
178
178
  </div>
179
179
  </div>
180
180
  <!-- END_VERBATIM -->
181
+
182
+ <a name="modifiers"></a>
183
+ ## Modifiers
184
+
185
+ <a name="inert"></a>
186
+ ### .inert
187
+
188
+ When building things like dialogs/modals, it's recommended to hide all the other elements on the page from screenreaders when trapping focus.
189
+
190
+ By adding `.inert` to `x-trap`, when focus is trapped, all other elements on the page will receive `aria-hidden="true"` attributes, and when focus trapping is disabled, those attributes will also be removed.
191
+
192
+ ```alpine
193
+ <!-- When `open` is `false`: -->
194
+ <body x-data="{ open: false }">
195
+ <div x-trap.inert="open" ...>
196
+ ...
197
+ </div>
198
+
199
+ <div>
200
+ ...
201
+ </div>
202
+ </body>
203
+
204
+ <!-- When `open` is `true`: -->
205
+ <body x-data="{ open: true }">
206
+ <div x-trap.inert="open" ...>
207
+ ...
208
+ </div>
209
+
210
+ <div aria-hidden="true">
211
+ ...
212
+ </div>
213
+ </body>
214
+ ```
215
+
216
+ <a name="noscroll"></a>
217
+ ### .noscroll
218
+
219
+ When building dialogs/modals with Alpine, it's recommended that you disable scrollling for the surrounding content when the dialog is open.
220
+
221
+ `x-trap` allows you to do this automatically with the `.noscroll` modifiers.
222
+
223
+ By adding `.noscroll`, Alpine will remove the scrollbar from the page and block users from scrolling down the page while a dialog is open.
224
+
225
+ For example:
226
+
227
+ ```alpine
228
+ <div x-data="{ open: false }">
229
+ <button>Open Dialog</button>
230
+
231
+ <div x-show="open" x-trap.noscroll="open">
232
+ Dialog Contents
233
+
234
+ <button @click="open = false">Close Dialog</button>
235
+ </div>
236
+ </div>
237
+ ```
238
+
239
+ <!-- START_VERBATIM -->
240
+ <div class="demo">
241
+ <div x-data="{ open: false }">
242
+ <button @click="open = true">Open Dialog</button>
243
+
244
+ <div x-show="open" x-trap.noscroll="open" class="border mt-4 p-4">
245
+ <div class="mb-4 text-bold">Dialog Contents</div>
246
+
247
+ <p class="mb-4 text-gray-600 text-sm">Notice how you can no longer scroll on this page while this dialog is open.</p>
248
+
249
+ <button class="mt-4" @click="open = false">Close Dialog</button>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ <!-- END_VERBATIM -->
@@ -40,7 +40,7 @@ Upgrading from Alpine V2 to V3 should be fairly painless. In many cases, NOTHING
40
40
  <a name="el-no-longer-root"></a>
41
41
  ### `$el` is now always the current element
42
42
 
43
- `$el` now always represents the element that an expression was executed on, not the root element of the component. This will replace most usages of `x-ref` and in the cases where you still want to access the root of a component, you can do so using `x-ref`. For example:
43
+ `$el` now always represents the element that an expression was executed on, not the root element of the component. This will replace most usages of `x-ref` and in the cases where you still want to access the root of a component, you can do so using `$root`. For example:
44
44
 
45
45
  ```alpine
46
46
  <!-- 🚫 Before -->
@@ -50,30 +50,15 @@ Upgrading from Alpine V2 to V3 should be fairly painless. In many cases, NOTHING
50
50
  </div>
51
51
 
52
52
  <!-- ✅ After -->
53
- <div x-data x-ref="root">
54
- <button @click="console.log($refs.root)"></button>
53
+ <div x-data>
54
+ <button @click="console.log($root)"></button>
55
55
  </div>
56
56
  ```
57
57
 
58
- For a smoother upgrade experience, you can optionally replace all instances of `$el` with a custom magic called `$root`, then add the following code to your site to mimic the behavior:
59
-
60
- ```alpine
61
- <script>
62
- document.addEventListener('alpine:init', () => {
63
- Alpine.magic('root', el => {
64
- let closestRootEl = (node) => {
65
- if (node.hasAttribute('x-data')) return node
66
-
67
- return closestRootEl(node.parentNode)
68
- }
69
-
70
- return closestRootEl(el)
71
- })
72
- })
73
- </script>
74
- ```
58
+ For a smoother upgrade experience, you can replace all instances of `$el` with a custom magic called `$root`.
75
59
 
76
- [→ Read more about $el in V3](/magics/el)
60
+ [→ Read more about $el in V3](/magics/el)
61
+ [→ Read more about $root in V3](/magics/root)
77
62
 
78
63
  <a name="auto-init"></a>
79
64
  ### Automatically evaluate `init()` functions defined on data object