x
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
<div class="tw:p-6 tw:max-w-7xl tw:mx-auto tw:space-y-8"> <div class="callout"> <p class="tw:mb-1 tw:text-sm tw:font-mono"> <strong>SLOT PICKER:</strong> Single-select radiogroup of booking time-slot chips, grouped by day column<br> <strong>COMPOSES:</strong> .empty-state (no slots available) · slot_picker_controller.js </p> <p class="tw:mb-0 tw:text-sm"> Used for open-day / interview slot booking (Events vertical). Click a slot to book it — only one slot can be selected across the whole picker. Arrow keys move focus between available slots without selecting (Enter/Space or click selects); taken slots are real <code>disabled</code> buttons, skipped automatically by both Tab and the arrow keys. </p> </div> <div class="tw:border-t tw:pt-6"> <h2 class="h4 tw:mb-4">Open day — some taken</h2> <div class="callout tw:mb-4"> <p class="tw:mb-0 tw:text-sm"> <strong>St Mary's Academy — Open Day.</strong> Three Saturday mornings, six 30-minute slots each. Taken slots are dimmed, unclickable, and carry a visible "Taken" label (never color alone) plus an <code>aria-label</code> that says so explicitly. </p> <p class="tw:mb-0 tw:text-sm"> <strong>Label in Name (WCAG 2.5.3):</strong> each chip's <code>aria-label</code> opens with the chip's own visible text, then adds the day — <code>aria-label="09:00, Saturday 12 September"</code>, not <code>"9:00 AM, Saturday 12 September"</code>. The date context is what makes a bare "09:00" unambiguous across three day columns, but it has to come <em>after</em> the visible string or a voice-control user saying "click 09:00" activates nothing. Taken chips render two lines, so their name leads with both — <code>aria-label="09:30 Taken, Saturday 12 September"</code>. </p> </div> <div data-controller="slot-picker" id="slot-picker-open-day"> <div class="slot-picker"> <div class="slot-picker-grid" role="radiogroup" aria-label="Choose an Open Day visit time"> <div> <div class="slot-picker-day">Sat 12 Sep</div> <div class="tw:flex tw:flex-wrap tw:gap-2"> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="0" aria-label="09:00, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T09:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="09:30 Taken, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T09:30" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">09:30</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:00, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T10:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="10:30 Taken, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T10:30" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">10:30</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:00, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T11:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:30, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T11:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:30</button> </div> </div> <div> <div class="slot-picker-day">Sat 19 Sep</div> <div class="tw:flex tw:flex-wrap tw:gap-2"> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="09:00 Taken, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T09:00" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">09:00</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T09:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:00, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T10:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T10:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="11:00 Taken, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T11:00" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">11:00</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="11:30 Taken, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T11:30" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">11:30</span> <span class="tw:block tw:font-normal">Taken</span> </button> </div> </div> <div> <div class="slot-picker-day">Sat 26 Sep</div> <div class="tw:flex tw:flex-wrap tw:gap-2"> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:00, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T09:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:30, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T09:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:00, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T10:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:30, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T10:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:00, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T11:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:30, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T11:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:30</button> </div> </div> </div> <div class="slot-picker-legend"> <span class="tw:inline-flex tw:items-center tw:gap-1.5"> <span class="tw:w-3 tw:h-3 tw:rounded-sm tw:border tw:border-line-accent tw:bg-white" aria-hidden="true"></span> Available </span> <span class="tw:inline-flex tw:items-center tw:gap-1.5"> <span class="tw:w-3 tw:h-3 tw:rounded-sm tw:bg-primary" aria-hidden="true"></span> Selected </span> <span class="tw:inline-flex tw:items-center tw:gap-1.5"> <span class="tw:w-3 tw:h-3 tw:rounded-sm tw:bg-line-muted tw:border tw:border-line-card" aria-hidden="true"></span> Taken </span> </div> <input type="hidden" name="visit_slot" data-slot-picker-target="value"> </div> <p class="form-text tw:mt-2">We'll email your confirmation as soon as you pick a time.</p> </div> <div class="tw:mt-4 tw:text-sm tw:text-gray-600"> <code><div data-controller="slot-picker"><div class="slot-picker"><div class="slot-picker-grid" role="radiogroup">…<button class="slot-picker-slot" role="radio" aria-checked="false">09:00</button>…</div><input type="hidden" data-slot-picker-target="value"></div></div></code> </div> </div> <div class="tw:border-t tw:pt-6"> <h2 class="h4 tw:mb-4">Preselected</h2> <div class="callout tw:mb-4"> <p class="tw:mb-0 tw:text-sm"> <strong>Editing an existing booking:</strong> the server renders the previously-booked slot with <code>class="selected"</code>, <code>aria-checked="true"</code>, and <code>tabindex="0"</code>. The controller reads this on connect, sets the hidden value, and leaves the roving tab stop on the already-selected slot. </p> </div> <div data-controller="slot-picker" id="slot-picker-preselected"> <div class="slot-picker"> <div class="slot-picker-grid" role="radiogroup" aria-label="Choose an interview time"> <div> <div class="slot-picker-day">Sat 19 Sep</div> <div class="tw:flex tw:flex-wrap tw:gap-2"> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:00, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T09:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T09:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:30</button> <button type="button" class="slot-picker-slot selected" role="radio" aria-checked="true" tabindex="0" aria-label="10:00, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T10:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T10:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="11:00 Taken, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T11:00" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">11:00</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T11:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:30</button> </div> </div> </div> <input type="hidden" name="interview_slot" value="2026-09-19T10:00" data-slot-picker-target="value"> </div> </div> </div> <div class="tw:border-t tw:pt-6"> <h2 class="h4 tw:mb-4">None available</h2> <div class="callout tw:mb-4"> <p class="tw:mb-0 tw:text-sm"> <strong>Fully booked date:</strong> when a day has zero available slots, the grid is replaced with <code>.empty-state</code> — no interactive picker is rendered at all, so there is nothing to focus that can't be used. </p> </div> <div class="slot-picker"> <div class="slot-picker-day">Sat 03 Oct</div> <div class="card"> <div class="empty-state"> <i class="fa-regular fa-calendar-xmark empty-state-icon" aria-hidden="true"></i> <h3 class="empty-state-title">No slots left for this date</h3> <p class="empty-state-text"> All Open Day visit slots for Saturday 3 October are booked. Try another date, or join the waiting list and we'll email you if a slot frees up. </p> <div class="empty-state-actions"> <button class="btn btn-primary" type="button">Choose another date</button> <button class="btn btn-outline-secondary" type="button">Join waiting list</button> </div> </div> </div> </div> <div class="tw:mt-4 tw:text-sm tw:text-gray-600"> <code><div class="slot-picker"><div class="card"><div class="empty-state">…</div></div></div></code> </div> </div></div>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
<div class="tw:p-6 tw:max-w-7xl tw:mx-auto tw:space-y-8"> <%# Introductory callout %> <div class="callout"> <p class="tw:mb-1 tw:text-sm tw:font-mono"> <strong>SLOT PICKER:</strong> Single-select radiogroup of booking time-slot chips, grouped by day column<br> <strong>COMPOSES:</strong> .empty-state (no slots available) · slot_picker_controller.js </p> <p class="tw:mb-0 tw:text-sm"> Used for open-day / interview slot booking (Events vertical). Click a slot to book it — only one slot can be selected across the whole picker. Arrow keys move focus between available slots without selecting (Enter/Space or click selects); taken slots are real <code>disabled</code> buttons, skipped automatically by both Tab and the arrow keys. </p> </div> <%# Open day — some taken %> <div class="tw:border-t tw:pt-6"> <h2 class="h4 tw:mb-4">Open day — some taken</h2> <div class="callout tw:mb-4"> <p class="tw:mb-0 tw:text-sm"> <strong>St Mary's Academy — Open Day.</strong> Three Saturday mornings, six 30-minute slots each. Taken slots are dimmed, unclickable, and carry a visible "Taken" label (never color alone) plus an <code>aria-label</code> that says so explicitly. </p> <p class="tw:mb-0 tw:text-sm"> <strong>Label in Name (WCAG 2.5.3):</strong> each chip's <code>aria-label</code> opens with the chip's own visible text, then adds the day — <code>aria-label="09:00, Saturday 12 September"</code>, not <code>"9:00 AM, Saturday 12 September"</code>. The date context is what makes a bare "09:00" unambiguous across three day columns, but it has to come <em>after</em> the visible string or a voice-control user saying "click 09:00" activates nothing. Taken chips render two lines, so their name leads with both — <code>aria-label="09:30 Taken, Saturday 12 September"</code>. </p> </div> <div data-controller="slot-picker" id="slot-picker-open-day"> <div class="slot-picker"> <div class="slot-picker-grid" role="radiogroup" aria-label="Choose an Open Day visit time"> <div> <div class="slot-picker-day">Sat 12 Sep</div> <div class="tw:flex tw:flex-wrap tw:gap-2"> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="0" aria-label="09:00, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T09:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="09:30 Taken, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T09:30" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">09:30</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:00, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T10:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="10:30 Taken, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T10:30" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">10:30</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:00, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T11:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:30, Saturday 12 September" data-slot-picker-target="slot" data-value="2026-09-12T11:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:30</button> </div> </div> <div> <div class="slot-picker-day">Sat 19 Sep</div> <div class="tw:flex tw:flex-wrap tw:gap-2"> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="09:00 Taken, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T09:00" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">09:00</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T09:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:00, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T10:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T10:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="11:00 Taken, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T11:00" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">11:00</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="11:30 Taken, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T11:30" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">11:30</span> <span class="tw:block tw:font-normal">Taken</span> </button> </div> </div> <div> <div class="slot-picker-day">Sat 26 Sep</div> <div class="tw:flex tw:flex-wrap tw:gap-2"> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:00, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T09:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:30, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T09:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:00, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T10:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:30, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T10:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:00, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T11:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:30, Saturday 26 September" data-slot-picker-target="slot" data-value="2026-09-26T11:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:30</button> </div> </div> </div> <div class="slot-picker-legend"> <span class="tw:inline-flex tw:items-center tw:gap-1.5"> <span class="tw:w-3 tw:h-3 tw:rounded-sm tw:border tw:border-line-accent tw:bg-white" aria-hidden="true"></span> Available </span> <span class="tw:inline-flex tw:items-center tw:gap-1.5"> <span class="tw:w-3 tw:h-3 tw:rounded-sm tw:bg-primary" aria-hidden="true"></span> Selected </span> <span class="tw:inline-flex tw:items-center tw:gap-1.5"> <span class="tw:w-3 tw:h-3 tw:rounded-sm tw:bg-line-muted tw:border tw:border-line-card" aria-hidden="true"></span> Taken </span> </div> <input type="hidden" name="visit_slot" data-slot-picker-target="value"> </div> <p class="form-text tw:mt-2">We'll email your confirmation as soon as you pick a time.</p> </div> <div class="tw:mt-4 tw:text-sm tw:text-gray-600"> <code><div data-controller="slot-picker"><div class="slot-picker"><div class="slot-picker-grid" role="radiogroup">…<button class="slot-picker-slot" role="radio" aria-checked="false">09:00</button>…</div><input type="hidden" data-slot-picker-target="value"></div></div></code> </div> </div> <%# Preselected %> <div class="tw:border-t tw:pt-6"> <h2 class="h4 tw:mb-4">Preselected</h2> <div class="callout tw:mb-4"> <p class="tw:mb-0 tw:text-sm"> <strong>Editing an existing booking:</strong> the server renders the previously-booked slot with <code>class="selected"</code>, <code>aria-checked="true"</code>, and <code>tabindex="0"</code>. The controller reads this on connect, sets the hidden value, and leaves the roving tab stop on the already-selected slot. </p> </div> <div data-controller="slot-picker" id="slot-picker-preselected"> <div class="slot-picker"> <div class="slot-picker-grid" role="radiogroup" aria-label="Choose an interview time"> <div> <div class="slot-picker-day">Sat 19 Sep</div> <div class="tw:flex tw:flex-wrap tw:gap-2"> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:00, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T09:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="09:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T09:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">09:30</button> <button type="button" class="slot-picker-slot selected" role="radio" aria-checked="true" tabindex="0" aria-label="10:00, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T10:00" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:00</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="10:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T10:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">10:30</button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" disabled aria-label="11:00 Taken, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T11:00" data-action="click->slot-picker#select keydown->slot-picker#keydown"> <span class="tw:block">11:00</span> <span class="tw:block tw:font-normal">Taken</span> </button> <button type="button" class="slot-picker-slot" role="radio" aria-checked="false" tabindex="-1" aria-label="11:30, Saturday 19 September" data-slot-picker-target="slot" data-value="2026-09-19T11:30" data-action="click->slot-picker#select keydown->slot-picker#keydown">11:30</button> </div> </div> </div> <input type="hidden" name="interview_slot" value="2026-09-19T10:00" data-slot-picker-target="value"> </div> </div> </div> <%# None available %> <div class="tw:border-t tw:pt-6"> <h2 class="h4 tw:mb-4">None available</h2> <div class="callout tw:mb-4"> <p class="tw:mb-0 tw:text-sm"> <strong>Fully booked date:</strong> when a day has zero available slots, the grid is replaced with <code>.empty-state</code> — no interactive picker is rendered at all, so there is nothing to focus that can't be used. </p> </div> <div class="slot-picker"> <div class="slot-picker-day">Sat 03 Oct</div> <div class="card"> <div class="empty-state"> <i class="fa-regular fa-calendar-xmark empty-state-icon" aria-hidden="true"></i> <h3 class="empty-state-title">No slots left for this date</h3> <p class="empty-state-text"> All Open Day visit slots for Saturday 3 October are booked. Try another date, or join the waiting list and we'll email you if a slot frees up. </p> <div class="empty-state-actions"> <button class="btn btn-primary" type="button">Choose another date</button> <button class="btn btn-outline-secondary" type="button">Join waiting list</button> </div> </div> </div> </div> <div class="tw:mt-4 tw:text-sm tw:text-gray-600"> <code><div class="slot-picker"><div class="card"><div class="empty-state">…</div></div></div></code> </div> </div></div>No notes provided.
No params configured.