@alpinejs/docs 3.6.1-revision.1 → 3.7.0-revision.2
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 +1 -1
- package/src/en/directives/teleport.md +155 -0
- package/src/en/essentials/installation.md +1 -1
- package/src/en/plugins/trap.md +18 -18
- package/src/en/start-here.md +1 -1
- package/src/en/plugins/portal.md +0 -220
package/package.json
CHANGED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
order: 12
|
|
3
|
+
title: teleport
|
|
4
|
+
description: Send Alpine templates to other parts of the DOM
|
|
5
|
+
graph_image: https://alpinejs.dev/social_teleport.jpg
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Teleport Plugin
|
|
9
|
+
|
|
10
|
+
The `x-teleport` directive allows you to transport part of your Alpine template to another part of the DOM on the page entirely.
|
|
11
|
+
|
|
12
|
+
This is useful for things like modals (especially nesting them), where it's helpful to break out of the z-index of the current Alpine component.
|
|
13
|
+
|
|
14
|
+
<a name="x-teleport"></a>
|
|
15
|
+
## x-teleport
|
|
16
|
+
|
|
17
|
+
By attaching `x-teleport` to a `<template>` element, you are telling Alpine to "append" that element to the provided selector.
|
|
18
|
+
|
|
19
|
+
> The `x-template` selector can be any string you would normally pass into something like `document.querySelector`
|
|
20
|
+
|
|
21
|
+
Here's a contrived modal example:
|
|
22
|
+
|
|
23
|
+
```alpine
|
|
24
|
+
<body>
|
|
25
|
+
<div x-data="{ open: false }">
|
|
26
|
+
<button @click="open = ! open">Toggle Modal</button>
|
|
27
|
+
|
|
28
|
+
<template x-teleport="body">
|
|
29
|
+
<div x-show="open">
|
|
30
|
+
Modal contents...
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div>Some other content placed AFTER the modal markup.</div>
|
|
36
|
+
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
</body>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
<!-- START_VERBATIM -->
|
|
43
|
+
<div class="demo" x-ref="root" id="modal2">
|
|
44
|
+
<div x-data="{ open: false }">
|
|
45
|
+
<button @click="open = ! open">Toggle Modal</button>
|
|
46
|
+
|
|
47
|
+
<template x-teleport="#modal2">
|
|
48
|
+
<div x-show="open">
|
|
49
|
+
Modal contents...
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div class="py-4">Some other content...</div>
|
|
56
|
+
</div>
|
|
57
|
+
<!-- END_VERBATIM -->
|
|
58
|
+
|
|
59
|
+
Notice how when toggling the modal, the actual modal contents show up AFTER the "Some other content..." element? This is because when Alpine is initializing, it sees `x-teleport="body"` and appends and initializes that element to the provided element selector.
|
|
60
|
+
|
|
61
|
+
<a name="forwarding-events"></a>
|
|
62
|
+
## Forwarding events
|
|
63
|
+
|
|
64
|
+
Alpine tries it's best to make the experience of teleporting seamless. Anything you would normally do in a template, you should be able to do inside an `x-teleport` template. Teleported content can access the normal Alpine scope of the component as well as other features like `$refs`, `$root`, etc...
|
|
65
|
+
|
|
66
|
+
However, native DOM events have no concept of teleportation, so if, for example, you trigger a "click" event from inside a teleported element, that event will bubble up the DOM tree as it normally would.
|
|
67
|
+
|
|
68
|
+
To make this experience more seamless, you can "forward" events by simply registering event listeners on the `<template x-teleport...>` element itself like so:
|
|
69
|
+
|
|
70
|
+
```alpine
|
|
71
|
+
<div x-data="{ open: false }">
|
|
72
|
+
<button @click="open = ! open">Toggle Modal</button>
|
|
73
|
+
|
|
74
|
+
<template x-teleport="body" @click="open = false">
|
|
75
|
+
<div x-show="open">
|
|
76
|
+
Modal contents...
|
|
77
|
+
(click to close)
|
|
78
|
+
</div>
|
|
79
|
+
</template>
|
|
80
|
+
</div>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
<!-- START_VERBATIM -->
|
|
84
|
+
<div class="demo" x-ref="root" id="modal3">
|
|
85
|
+
<div x-data="{ open: false }">
|
|
86
|
+
<button @click="open = ! open">Toggle Modal</button>
|
|
87
|
+
|
|
88
|
+
<template x-teleport="#modal3" @click="open = false">
|
|
89
|
+
<div x-show="open">
|
|
90
|
+
Modal contents...
|
|
91
|
+
<div>(click to close)</div>
|
|
92
|
+
</div>
|
|
93
|
+
</template>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<!-- END_VERBATIM -->
|
|
97
|
+
|
|
98
|
+
Notice how we are now able to listen for events dispatched from within the teleported element from outside the `<template>` element itself?
|
|
99
|
+
|
|
100
|
+
Alpine does this by looking for event listeners registered on `<template x-teleport...>` and stops those events from propogating past the live, teleported, DOM element. Then, it creates a copy of that event and re-dispatches it from `<template x-teleport...>`.
|
|
101
|
+
|
|
102
|
+
<a name="nesting"></a>
|
|
103
|
+
## Nesting
|
|
104
|
+
|
|
105
|
+
Teleporting is especially helpful if you are trying to nest one modal within another. Alpine makes it simple to do so:
|
|
106
|
+
|
|
107
|
+
```alpine
|
|
108
|
+
<div x-data="{ open: false }">
|
|
109
|
+
<button @click="open = ! open">Toggle Modal</button>
|
|
110
|
+
|
|
111
|
+
<template x-teleport="body">
|
|
112
|
+
<div x-show="open">
|
|
113
|
+
Modal contents...
|
|
114
|
+
|
|
115
|
+
<div x-data="{ open: false }">
|
|
116
|
+
<button @click="open = ! open">Toggle Nested Modal</button>
|
|
117
|
+
|
|
118
|
+
<template x-teleport="body">
|
|
119
|
+
<div x-show="open">
|
|
120
|
+
Nested modal contents...
|
|
121
|
+
</div>
|
|
122
|
+
</template>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</template>
|
|
126
|
+
</div>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
<!-- START_VERBATIM -->
|
|
130
|
+
<div class="demo" x-ref="root" id="modal4">
|
|
131
|
+
<div x-data="{ open: false }">
|
|
132
|
+
<button @click="open = ! open">Toggle Modal</button>
|
|
133
|
+
|
|
134
|
+
<template x-teleport="#modal4">
|
|
135
|
+
<div x-show="open">
|
|
136
|
+
<div class="py-4">Modal contents...</div>
|
|
137
|
+
|
|
138
|
+
<div x-data="{ open: false }">
|
|
139
|
+
<button @click="open = ! open">Toggle Nested Modal</button>
|
|
140
|
+
|
|
141
|
+
<template x-teleport="#modal4">
|
|
142
|
+
<div class="pt-4" x-show="open">
|
|
143
|
+
Nested modal contents...
|
|
144
|
+
</div>
|
|
145
|
+
</template>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</template>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<template x-teleport-target="modals3"></template>
|
|
152
|
+
</div>
|
|
153
|
+
<!-- END_VERBATIM -->
|
|
154
|
+
|
|
155
|
+
After toggling "on" both modals, they are authored as children, but will be rendered as sibling elements on the page, not within one another.
|
|
@@ -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.
|
|
36
|
+
<script defer src="https://unpkg.com/alpinejs@3.7.0/dist/cdn.min.js"></script>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
That's it! Alpine is now available for use inside your page.
|
package/src/en/plugins/trap.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
order: 3
|
|
3
3
|
title: Trap
|
|
4
|
-
description: Easily trap page focus within an element (modals,
|
|
4
|
+
description: Easily trap page focus within an element (modals, dialogs, etc...)
|
|
5
5
|
graph_image: https://alpinejs.dev/social_trap.jpg
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ graph_image: https://alpinejs.dev/social_trap.jpg
|
|
|
9
9
|
|
|
10
10
|
Alpine's Trap plugin allows you to conditionally trap focus inside an element.
|
|
11
11
|
|
|
12
|
-
This is useful for modals and other
|
|
12
|
+
This is useful for modals and other dialog elements.
|
|
13
13
|
|
|
14
14
|
<a name="installation"></a>
|
|
15
15
|
## Installation
|
|
@@ -58,7 +58,7 @@ For example:
|
|
|
58
58
|
|
|
59
59
|
```alpine
|
|
60
60
|
<div x-data="{ open: false }">
|
|
61
|
-
<button @click="open = true">Open
|
|
61
|
+
<button @click="open = true">Open Dialog</button>
|
|
62
62
|
|
|
63
63
|
<span x-show="open" x-trap="open">
|
|
64
64
|
<p>...</p>
|
|
@@ -67,7 +67,7 @@ For example:
|
|
|
67
67
|
|
|
68
68
|
<input type="text" placeholder="Some other input...">
|
|
69
69
|
|
|
70
|
-
<button @click="open = false">Close
|
|
70
|
+
<button @click="open = false">Close Dialog</button>
|
|
71
71
|
</span>
|
|
72
72
|
</div>
|
|
73
73
|
```
|
|
@@ -75,12 +75,12 @@ For example:
|
|
|
75
75
|
<!-- START_VERBATIM -->
|
|
76
76
|
<div x-data="{ open: false }" class="demo">
|
|
77
77
|
<div :class="open && 'opacity-50'">
|
|
78
|
-
<button x-on:click="open = true">Open
|
|
78
|
+
<button x-on:click="open = true">Open Dialog</button>
|
|
79
79
|
</div>
|
|
80
80
|
|
|
81
81
|
<div x-show="open" x-trap="open" class="mt-4 space-y-4 p-4 border bg-yellow-100" @keyup.escape.window="open = false">
|
|
82
82
|
<strong>
|
|
83
|
-
<div>Focus is now "trapped" inside this
|
|
83
|
+
<div>Focus is now "trapped" inside this dialog, meaning you can only click/focus elements within this yellow dialog. If you press tab repeatedly, the focus will stay within this dialog.</div>
|
|
84
84
|
</strong>
|
|
85
85
|
|
|
86
86
|
<div>
|
|
@@ -92,16 +92,16 @@ For example:
|
|
|
92
92
|
</div>
|
|
93
93
|
|
|
94
94
|
<div>
|
|
95
|
-
<button @click="open = false">Close
|
|
95
|
+
<button @click="open = false">Close Dialog</button>
|
|
96
96
|
</div>
|
|
97
97
|
</div>
|
|
98
98
|
</div>
|
|
99
99
|
<!-- END_VERBATIM -->
|
|
100
100
|
|
|
101
101
|
<a name="nesting"></a>
|
|
102
|
-
## Nesting
|
|
102
|
+
## Nesting dialogs
|
|
103
103
|
|
|
104
|
-
Sometimes you may want to nest one
|
|
104
|
+
Sometimes you may want to nest one dialog inside another. `x-trap` makes this trivial and handles it automatically.
|
|
105
105
|
|
|
106
106
|
`x-trap` keeps track of newly "trapped" elements and stores the last actively focused element. Once the element is "untrapped" then the focus will be returned to where it was originally.
|
|
107
107
|
|
|
@@ -111,24 +111,24 @@ Here is nesting in action:
|
|
|
111
111
|
|
|
112
112
|
```alpine
|
|
113
113
|
<div x-data="{ open: false }">
|
|
114
|
-
<button @click="open = true">Open
|
|
114
|
+
<button @click="open = true">Open Dialog</button>
|
|
115
115
|
|
|
116
116
|
<span x-show="open" x-trap="open">
|
|
117
117
|
|
|
118
118
|
...
|
|
119
119
|
|
|
120
120
|
<div x-data="{ open: false }">
|
|
121
|
-
<button @click="open = true">Open Nested
|
|
121
|
+
<button @click="open = true">Open Nested Dialog</button>
|
|
122
122
|
|
|
123
123
|
<span x-show="open" x-trap="open">
|
|
124
124
|
|
|
125
125
|
...
|
|
126
126
|
|
|
127
|
-
<button @click="open = false">Close Nested
|
|
127
|
+
<button @click="open = false">Close Nested Dialog</button>
|
|
128
128
|
</span>
|
|
129
129
|
</div>
|
|
130
130
|
|
|
131
|
-
<button @click="open = false">Close
|
|
131
|
+
<button @click="open = false">Close Dialog</button>
|
|
132
132
|
</span>
|
|
133
133
|
</div>
|
|
134
134
|
```
|
|
@@ -136,7 +136,7 @@ Here is nesting in action:
|
|
|
136
136
|
<!-- START_VERBATIM -->
|
|
137
137
|
<div x-data="{ open: false }" class="demo">
|
|
138
138
|
<div :class="open && 'opacity-50'">
|
|
139
|
-
<button x-on:click="open = true">Open
|
|
139
|
+
<button x-on:click="open = true">Open Dialog</button>
|
|
140
140
|
</div>
|
|
141
141
|
|
|
142
142
|
<div x-show="open" x-trap="open" class="mt-4 space-y-4 p-4 border bg-yellow-100" @keyup.escape.window="open = false">
|
|
@@ -150,12 +150,12 @@ Here is nesting in action:
|
|
|
150
150
|
|
|
151
151
|
<div x-data="{ open: false }">
|
|
152
152
|
<div :class="open && 'opacity-50'">
|
|
153
|
-
<button x-on:click="open = true">Open Nested
|
|
153
|
+
<button x-on:click="open = true">Open Nested Dialog</button>
|
|
154
154
|
</div>
|
|
155
155
|
|
|
156
156
|
<div x-show="open" x-trap="open" class="mt-4 space-y-4 p-4 border border-gray-500 bg-yellow-200" @keyup.escape.window="open = false">
|
|
157
157
|
<strong>
|
|
158
|
-
<div>Focus is now "trapped" inside this nested
|
|
158
|
+
<div>Focus is now "trapped" inside this nested dialog. You cannot focus anything inside the outer dialog while this is open. If you close this dialog, focus will be returned to the last known active element.</div>
|
|
159
159
|
</strong>
|
|
160
160
|
|
|
161
161
|
<div>
|
|
@@ -167,13 +167,13 @@ Here is nesting in action:
|
|
|
167
167
|
</div>
|
|
168
168
|
|
|
169
169
|
<div>
|
|
170
|
-
<button @click="open = false">Close Nested
|
|
170
|
+
<button @click="open = false">Close Nested Dialog</button>
|
|
171
171
|
</div>
|
|
172
172
|
</div>
|
|
173
173
|
</div>
|
|
174
174
|
|
|
175
175
|
<div>
|
|
176
|
-
<button @click="open = false">Close
|
|
176
|
+
<button @click="open = false">Close Dialog</button>
|
|
177
177
|
</div>
|
|
178
178
|
</div>
|
|
179
179
|
</div>
|
package/src/en/start-here.md
CHANGED
|
@@ -88,7 +88,7 @@ You can listen for other events as you'd imagine. For example, listening for a `
|
|
|
88
88
|
|
|
89
89
|
When a `click` event happens, Alpine will call the associated JavaScript expression, `count++` in our case. As you can see, we have direct access to data declared in the `x-data` expression.
|
|
90
90
|
|
|
91
|
-
> You will often see `@` instead of `x-on
|
|
91
|
+
> You will often see `@` instead of `x-on:`. This is a shorter, friendlier syntax that many prefer. From now on, this documentation will likely use `@` instead of `x-on:`.
|
|
92
92
|
|
|
93
93
|
[→ Read more about `x-on`](/directives/on)
|
|
94
94
|
|
package/src/en/plugins/portal.md
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
order: 6
|
|
3
|
-
title: Portal
|
|
4
|
-
description: Send Alpine templates to other parts of the DOM
|
|
5
|
-
graph_image: https://alpinejs.dev/social_portal.jpg
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Portal Plugin
|
|
9
|
-
|
|
10
|
-
Alpine's Portal plugin allows you to transport part of your Alpine template to another part of the DOM on the page entirely.
|
|
11
|
-
|
|
12
|
-
This is useful for things like modals (especially nesting them), where it's helpful to break out of the z-index of the current Alpine component.
|
|
13
|
-
|
|
14
|
-
> Note: this plugin is currently in beta while it is being tested in the public. Be warned that it may change before being officially released.
|
|
15
|
-
|
|
16
|
-
<a name="installation"></a>
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
You can use this plugin by either including it from a `<script>` tag or installing it via NPM:
|
|
20
|
-
|
|
21
|
-
### Via CDN
|
|
22
|
-
|
|
23
|
-
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.
|
|
24
|
-
|
|
25
|
-
```alpine
|
|
26
|
-
<!-- Alpine Plugins -->
|
|
27
|
-
<script defer src="https://unpkg.com/@alpinejs/portal@3.6.0-beta.0/dist/cdn.min.js"></script>
|
|
28
|
-
|
|
29
|
-
<!-- Alpine Core -->
|
|
30
|
-
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Via NPM
|
|
34
|
-
|
|
35
|
-
You can install Portal from NPM for use inside your bundle like so:
|
|
36
|
-
|
|
37
|
-
```shell
|
|
38
|
-
npm install @alpinejs/portal
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Then initialize it from your bundle:
|
|
42
|
-
|
|
43
|
-
```js
|
|
44
|
-
import Alpine from 'alpinejs'
|
|
45
|
-
import portal from '@alpinejs/portal'
|
|
46
|
-
|
|
47
|
-
Alpine.plugin(portal)
|
|
48
|
-
|
|
49
|
-
...
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
<a name="usage"></a>
|
|
53
|
-
## Usage
|
|
54
|
-
|
|
55
|
-
Everytime you use a portal, you will need two different directives: `x-portal` and `x-portal-target`.
|
|
56
|
-
|
|
57
|
-
By attaching `x-portal` to a `<template>` element, you are telling Alpine to send that DOM content to another template element that has a matching `x-portal-target` on it.
|
|
58
|
-
|
|
59
|
-
Here's a contrived modal example using portals:
|
|
60
|
-
|
|
61
|
-
```alpine
|
|
62
|
-
<div x-data="{ open: false }">
|
|
63
|
-
<button @click="open = ! open">Toggle Modal</button>
|
|
64
|
-
|
|
65
|
-
<template x-portal="modals">
|
|
66
|
-
<div x-show="open">
|
|
67
|
-
Modal contents...
|
|
68
|
-
</div>
|
|
69
|
-
</template>
|
|
70
|
-
|
|
71
|
-
<div class="py-4">Some other content placed AFTER the modal markup.</div>
|
|
72
|
-
</div>
|
|
73
|
-
|
|
74
|
-
<template x-portal-target="modals"></template>
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
<!-- START_VERBATIM -->
|
|
78
|
-
<div class="demo" x-ref="root">
|
|
79
|
-
<div x-data="{ open: false }">
|
|
80
|
-
<button @click="open = ! open">Toggle Modal</button>
|
|
81
|
-
|
|
82
|
-
<template x-portal="modals">
|
|
83
|
-
<div x-show="open">
|
|
84
|
-
Modal contents...
|
|
85
|
-
</div>
|
|
86
|
-
</template>
|
|
87
|
-
|
|
88
|
-
<div class="py-4">Some other content...</div>
|
|
89
|
-
</div>
|
|
90
|
-
|
|
91
|
-
<template x-portal-target="modals"></template>
|
|
92
|
-
</div>
|
|
93
|
-
<!-- END_VERBATIM -->
|
|
94
|
-
|
|
95
|
-
Notice how when toggling the modal, the actual modal contents show up AFTER the "Some other content..." element? This is because when Alpine is initializing, it sees `x-portal="modals"` and takes that markup out of the page waiting until it finds an element with `x-portal-target="modals"` to insert it into.
|
|
96
|
-
|
|
97
|
-
<a name="forwarding-events"></a>
|
|
98
|
-
## Forwarding events
|
|
99
|
-
|
|
100
|
-
Alpine tries it's best to make the experience of using portals seemless. Anything you would normally do in a template, you should be able to do inside a portal. Portal content can access the normal Alpine scope of the component as well as other features like `$refs`, `$root`, etc...
|
|
101
|
-
|
|
102
|
-
However, native DOM events have no concept of portals, so if, for example, you trigger a "click" event from inside a portal, that event will bubble up the DOM tree as it normally would ignoring the fact that it is within a portal.
|
|
103
|
-
|
|
104
|
-
To make this experience more seemless, you can "forward" events by simply registering event listeners on the portal's `<template>` element itself like so:
|
|
105
|
-
|
|
106
|
-
```alpine
|
|
107
|
-
<div x-data="{ open: false }">
|
|
108
|
-
<button @click="open = ! open">Toggle Modal</button>
|
|
109
|
-
|
|
110
|
-
<template x-portal="modals" @click="open = false">
|
|
111
|
-
<div x-show="open">
|
|
112
|
-
Modal contents...
|
|
113
|
-
(click to close)
|
|
114
|
-
</div>
|
|
115
|
-
</template>
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
<template x-portal-target="modals"></template>
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
<!-- START_VERBATIM -->
|
|
122
|
-
<div class="demo" x-ref="root">
|
|
123
|
-
<div x-data="{ open: false }">
|
|
124
|
-
<button @click="open = ! open">Toggle Modal</button>
|
|
125
|
-
|
|
126
|
-
<template x-portal="modals" @click="open = false">
|
|
127
|
-
<div x-show="open">
|
|
128
|
-
Modal contents...<br>
|
|
129
|
-
(click to close)
|
|
130
|
-
</div>
|
|
131
|
-
</template>
|
|
132
|
-
</div>
|
|
133
|
-
|
|
134
|
-
<template x-portal-target="modals"></template>
|
|
135
|
-
</div>
|
|
136
|
-
<!-- END_VERBATIM -->
|
|
137
|
-
|
|
138
|
-
Notice how we are now able to listen for events dispatched from within the portal from outside the portal itself?
|
|
139
|
-
|
|
140
|
-
Alpine does this by looking for event listeners registered on `<template x-portal...` and stops those events from propogating past the `<template x-portal-target...` element. Then it creates a copy of that event and re-dispatches it from `<template x-portal`.
|
|
141
|
-
|
|
142
|
-
<a name="nesting-portals"></a>
|
|
143
|
-
## Nesting portals
|
|
144
|
-
|
|
145
|
-
Portals are especially helpful if you are trying to nest one modal within another. Alpine makes it simple to do so:
|
|
146
|
-
|
|
147
|
-
```alpine
|
|
148
|
-
<div x-data="{ open: false }">
|
|
149
|
-
<button @click="open = ! open">Toggle Modal</button>
|
|
150
|
-
|
|
151
|
-
<template x-portal="modals">
|
|
152
|
-
<div x-show="open">
|
|
153
|
-
Modal contents...
|
|
154
|
-
|
|
155
|
-
<div x-data="{ open: false }">
|
|
156
|
-
<button @click="open = ! open">Toggle Nested Modal</button>
|
|
157
|
-
|
|
158
|
-
<template x-portal="modals">
|
|
159
|
-
<div x-show="open">
|
|
160
|
-
Nested modal contents...
|
|
161
|
-
</div>
|
|
162
|
-
</template>
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
</template>
|
|
166
|
-
</div>
|
|
167
|
-
|
|
168
|
-
<template x-portal-target="modals"></template>
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
<!-- START_VERBATIM -->
|
|
172
|
-
<div class="demo" x-ref="root">
|
|
173
|
-
<div x-data="{ open: false }">
|
|
174
|
-
<button @click="open = ! open">Toggle Modal</button>
|
|
175
|
-
|
|
176
|
-
<template x-portal="modals">
|
|
177
|
-
<div x-show="open">
|
|
178
|
-
<div class="py-4">Modal contents...</div>
|
|
179
|
-
|
|
180
|
-
<div x-data="{ open: false }">
|
|
181
|
-
<button @click="open = ! open">Toggle Nested Modal</button>
|
|
182
|
-
|
|
183
|
-
<template x-portal="modals">
|
|
184
|
-
<div class="pt-4" x-show="open">
|
|
185
|
-
Nested modal contents...
|
|
186
|
-
</div>
|
|
187
|
-
</template>
|
|
188
|
-
</div>
|
|
189
|
-
</div>
|
|
190
|
-
</template>
|
|
191
|
-
</div>
|
|
192
|
-
|
|
193
|
-
<template x-portal-target="modals"></template>
|
|
194
|
-
</div>
|
|
195
|
-
<!-- END_VERBATIM -->
|
|
196
|
-
|
|
197
|
-
After toggling "on" both modals, they are authored as children, but will be rendered as sibling elements on the page, not within one another.
|
|
198
|
-
|
|
199
|
-
<a name="multiple-portals"></a>
|
|
200
|
-
## Handling multiple portals
|
|
201
|
-
|
|
202
|
-
Suppose you have multiple modals on a page, but a single `<template x-portal-target="modal">` element.
|
|
203
|
-
|
|
204
|
-
Alpine automatically appends extra elements with `x-portal="modals"` at the target. No need for any extra syntax:
|
|
205
|
-
|
|
206
|
-
```alpine
|
|
207
|
-
<template x-portal="modals">
|
|
208
|
-
...
|
|
209
|
-
</template>
|
|
210
|
-
|
|
211
|
-
<template x-portal="modals">
|
|
212
|
-
...
|
|
213
|
-
</template>
|
|
214
|
-
|
|
215
|
-
...
|
|
216
|
-
|
|
217
|
-
<template x-portal-target="modals"></template>
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Now both of these modals will be rendered where `<template x-portal-target="modals">` lives.
|