SlotPicker
SlotPicker accepts free slots as UTC ISO timestamps and groups them by day in the active IANA display zone. Choose it for public booking; use TimePicker when the application is collecting a local time rather than showing availability that already exists as instants.
Examples
Choose then confirm a slot
Slots stay UTC at the API boundary, but the calendar day and clock time shown here are computed in
timezone. Selecting a time reveals a separate confirmation action, where the server should
revalidate it.
Translate the embedded zone picker
labels.timeZonePicker is forwarded directly to the embedded TimeZonePicker. Keep those nested
labels with the SlotPicker translation so the change-time-zone path does not fall back to English.
When to use
Use SlotPicker when a person needs to browse finite, server-provided availability and confirm one slot.
Reach for something else when:
- The person is entering an arbitrary local time — use TimePicker or TimeInput.
- The application is defining availability — use WeeklyScheduleEditor before producing bookable instants.
- The application is showing a broader calendar of events — use CalendarView.
Accessibility
- Available times are a named
role="listbox"; each time is a native button withrole="option"andaria-selected. A selected slot is followed by the native confirmation button. - The changing availability area is
aria-live="polite", including its loading skeleton and empty states. The embedded TimeZonePicker retains its searchable combobox keyboard behavior. - Calendar days with availability receive a visual marker and unavailable days are disabled. Visible and
accessible date, time, hold and time-zone strings are configurable through
localeandlabels.
API and code
| Name | Type | Required | Description |
|---|---|---|---|
slots | Slot[] | — | Free slots in UTC. The component groups them by active display-zone day. |
date | string | — | Controlled visible local YYYY-MM-DD day. |
defaultDate | string | — | Initial visible local YYYY-MM-DD day. |
onDateChange | (isoDate: string) => void | — | Called after the visible local day changes. |
timezone | string | — | Controlled IANA display zone. Defaults to the browser-detected zone. |
onTimezoneChange | (zone: string) => void | — | Called after the active IANA display zone changes. |
detectedZone | string | — | IANA zone shown as detected in the embedded TimeZonePicker. |
onConfirm | (slot: Slot) => void | — | Called after a user confirms a selected slot. Revalidate on the server. |
confirmLabel | string | — | Confirmation button text. Default: Confirm. |
holdExpiresAt | string | — | UTC ISO temporary-hold expiry. Its remaining duration is visible. |
nextAvailableDate | string | — | Local YYYY-MM-DD target for an empty-day shortcut. |
loading | boolean | — | Renders six slot pills while availability loads. |
emptyMessage | string | — | Empty visible-day message. |
fullMessage | string | — | Message when no slots exist in any day. |
locale | string | — | BCP 47 locale used for display times and dates. Default: en-US. |
min | Date | string | — | Inclusive local calendar lower limit. |
max | Date | string | — | Inclusive local calendar upper limit. |
children | ReactNode | — | Summary content rendered above the calendar. |
labels | SlotPickerLabels | — | Translatable visible and accessible labels, merged over English defaults. |
x-data="lyraSlotPicker({ … })"
| Option | Type | Required | Description |
|---|---|---|---|
slots | readonly LyraSlot[] | — | Free slots in UTC. They are grouped by the active display-zone day. |
date | string | null | — | Initial visible local `YYYY-MM-DD` day; modelable after initialization. |
timezone | string | — | Initial IANA display zone; modelable after initialization. |
detectedZone | string | — | IANA zone shown as detected in the embedded time-zone picker. |
holdExpiresAt | string | null | — | UTC ISO temporary-hold expiry. |
nextAvailableDate | string | — | Local `YYYY-MM-DD` target for an empty-day shortcut. |
loading | boolean | — | Renders six slot pills while availability loads. |
locale | string | — | BCP 47 locale used for display times and dates. Default: `"en-US"`. |
min | string | — | Inclusive local calendar lower limit. |
max | string | — | Inclusive local calendar upper limit. |
labels | LyraSlotPickerLabels | — | Translatable labels merged over English defaults. |
tzLabels | LyraTimeZonePickerLabels | — | Labels forwarded unchanged to the nested time-zone picker. |
Without React, group UTC instants using the chosen display zone before rendering these classes:
<div class="lyra-slotpicker">
<div class="lyra-slotpicker__side">August 3, 2026 · New York</div>
<div class="lyra-slotpicker__main" aria-live="polite">
<span class="lyra-slotpicker__daylabel">Monday, August 3</span>
<div
class="lyra-slotpicker__slots"
role="listbox"
aria-label="Available times for Monday, August 3"
>
<button class="lyra-slotpicker__slot" type="button" role="option" aria-selected="false">
09:00 AM
</button>
</div>
</div>
</div><lyra:slot-picker> Generated from lyra-ds/blade v0.10.0.
The behavior comes from lyraSlotPicker() — install @lyra-ds/alpine and see the HTML + Alpine tab.
| Prop | Default | Required | Example values |
|---|---|---|---|
slots | [] | — | — |
date | null | — | — |
timezone | null | — | America/Sao_Paulo |
detectedZone | null | — | — |
holdExpiresAt | null | — | 2099-08-10T13:02:05Z |
nextAvailableDate | null | — | — |
loading | false | — | — |
locale | 'en-US' | — | — |
min | null | — | — |
max | null | — | — |
labels | [] | — | — |
tzLabels | [] | — | — |
<lyra:slot-picker
date="2026-03-17"
timezone="America/Sao_Paulo"
locale="en-US"
:slots="[
['start' => '2026-03-17T13:00:00Z', 'end' => '2026-03-17T13:30:00Z'],
['start' => '2026-03-17T14:00:00Z', 'end' => '2026-03-17T14:30:00Z'],
['start' => '2026-03-17T15:30:00Z', 'end' => '2026-03-17T16:00:00Z'],
]"
/>