Schedule Picker
import { SchedulePicker } from '@absoluteui/components/schedule-picker';import '@absoluteui/components/date-input/style.css';Using Angular? See Schedule Picker for Angular.
What it does
Section titled “What it does”Chooses when something happens, in one form control: start and end, all-day or timed, in a timezone, optionally repeating. Timed schedules use two DateTime Pickers (instants whose wall-clock times are read in the schedule’s timezone); all-day schedules use two Date Pickers (inclusive days). An optional timezone select re-reads the entered times in another zone; an optional Recurrence Picker (recurrence: true) edits the repetition with the schedule start as its series start.
Moving the start keeps the duration. The value is a ScheduleValue; the form value is iCalendar text (DTSTART, DTEND, RRULE, EXDATE), with scheduleToString and parseSchedule to convert.
When to use
Section titled “When to use”- Event, meeting, booking, or maintenance-window editors.
- Anything with a start, an end, and optionally a repetition, where timezones matter.
When not to use
Section titled “When not to use”- A single moment: use DateTime Picker.
- A range of dates without times: Date Range Picker is lighter.
- A duration without a start: use Duration Picker.
Examples
Section titled “Examples”A meeting with timezone choice and repetition
Section titled “A meeting with timezone choice and repetition”import { parseInstant } from '@absoluteui/core';import { SchedulePicker, scheduleToString, type SchedulePickerChangeDetail } from '@absoluteui/components/schedule-picker';
const start = parseInstant('2026-09-29T08:00:00Z');const end = parseInstant('2026-09-29T09:00:00Z');const host = document.createElement('div');document.body.append(host);if (start && end) { SchedulePicker.create(host, { label: 'When', name: 'when', value: { allDay: false, start, end, timeZone: 'Europe/London', recurrence: null }, timeZones: ['Europe/London', 'America/New_York', 'Asia/Kolkata'], recurrence: true, });}host.addEventListener('aui-change', (event) => { const { value } = (event as CustomEvent<SchedulePickerChangeDetail>).detail; host.dataset.ical = value ? scheduleToString(value) : '';});Load and save iCalendar text
Section titled “Load and save iCalendar text”import { parseSchedule, SchedulePicker } from '@absoluteui/components/schedule-picker';
const saved = 'DTSTART;VALUE=DATE:20261224\nDTEND;VALUE=DATE:20261227';const host = document.createElement('div');document.body.append(host);const picker = SchedulePicker.create(host, { label: 'Office closed', value: parseSchedule(saved), required: true });export const text = picker.getFormValue();Default duration of new timed schedules
Section titled “Default duration of new timed schedules”import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { schedulePicker: { defaultDuration: 30 } } });import { parseInstant } from '@absoluteui/core';import { SchedulePicker, scheduleToString, type SchedulePickerChangeDetail } from '@absoluteui/components/schedule-picker';import '@absoluteui/components/date-input/style.css';import '@absoluteui/components/calendar/style.css';import '@absoluteui/components/date-picker/style.css';import '@absoluteui/components/date-time-picker/style.css';import '@absoluteui/components/recurrence-picker/style.css';import '@absoluteui/components/schedule-picker/style.css';
const start = parseInstant('2026-09-29T08:00:00Z');const end = parseInstant('2026-09-29T09:00:00Z');const host = document.querySelector<HTMLElement>('#when');if (host && start && end) { SchedulePicker.create(host, { label: 'When', name: 'when', recurrence: true, timeZones: ['Europe/London', 'America/New_York'], value: { allDay: false, start, end, timeZone: 'Europe/London', recurrence: null } }); host.addEventListener('aui-change', (event) => { const { value } = (event as CustomEvent<SchedulePickerChangeDetail>).detail; host.dataset.ical = value ? scheduleToString(value) : ''; });}More usage
Section titled “More usage”See section 33 and metadata/schedule-picker/examples.json: meeting with timezone and recurrence, iCalendar round trip, global configuration.
Anatomy
Section titled “Anatomy”<div class="aui-field aui-schedule-picker [--all-day] [--invalid] [--disabled]"> (consumer host) <fieldset class="aui-schedule-picker__fieldset" aria-describedby="{help} {error} {duration}"> <legend class="aui-field__label">When</legend> <div class="aui-schedule-picker__range"> <div class="aui-schedule-picker__part --start"> DateTime Picker "Starts" <div class="aui-schedule-picker__part --start-date" hidden> Date Picker "Start date" <div class="aui-schedule-picker__part --end"> DateTime Picker "Ends" <div class="aui-schedule-picker__part --end-date" hidden> Date Picker "End date" <p class="aui-schedule-picker__duration">Duration: 1 hr, 30 min</p> <div class="aui-schedule-picker__row"><label class="…__check"><input type="checkbox" class="…__checkbox"> All day</label> <div class="aui-schedule-picker__row --zone"><label>Time zone</label><select class="…__select"> <div class="aui-schedule-picker__recurrence"> Recurrence Picker "Repeat" (with recurrence) <div class="aui-field__description"> <div class="aui-field__error"> <input type="hidden" name="...">API reference
Section titled “API reference”Factory
Section titled “Factory”SchedulePicker.create(host: HTMLElement, options: SchedulePickerOptions): SchedulePickerGlobal configuration key: schedulePicker (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Legend of the fieldset (required accessible name). Required. | |
hideLabel |
boolean |
false |
Visually hide the legend. |
value |
ScheduleValue | null |
Timed ({ allDay: false, start: Instant, end: Instant, timeZone, recurrence }) or all-day ({ allDay: true, start: PlainDate, end: PlainDate (inclusive), timeZone, recurrence }). | |
allowAllDay |
boolean |
true |
Offer the all-day checkbox. |
timeZones |
readonly string[] |
Timezones offered in a select; omitted: no select. | |
recurrence |
boolean |
false |
Embed a Recurrence Picker (read at creation). Set at creation only. |
name |
string |
Form field name of the hidden input (iCalendar text). | |
description |
string |
Help text referenced by the fieldset. | |
required |
boolean |
false |
An empty schedule is invalid. |
disabled |
boolean |
false |
Disables every part; not submitted. |
firstDayOfWeek |
IsoWeekday |
First column of the calendars and weekday toggles. | |
validate |
(value: ScheduleValue | null) => string | null |
Consumer validation after built-in checks. | |
icons |
Partial<{ error: IconRef }> |
Icon slot overrides. | |
validationTiming |
'blur' | 'input' | 'submit' |
"blur" |
When validation messages first appear. Globally configurable. |
defaultDuration |
number |
60 |
Minutes of a new timed schedule after switching off all-day. Globally configurable. |
locale |
string |
"en-US" |
Month and weekday names, dates, numbers, the first day of the week, and messages. Globally configurable. Inherited from common configuration. |
timezone |
string |
"UTC" |
Timezone of the wall-clock times when the value has none and no select is shown. Globally configurable. Inherited from common configuration. |
disambiguation |
'compatible' | 'earlier' | 'later' | 'reject' |
"compatible" |
DST policy for wall-clock times in a gap or overlap. Globally configurable. Inherited from common configuration. |
direction |
'ltr' | 'rtl' |
"ltr" |
Reading direction; Left/Right arrow keys and chevrons follow it. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer host. |
fieldset |
HTMLFieldSetElement |
The labelled fieldset. |
startPicker / endPicker |
DateTimePicker |
Timed pickers (hidden while all-day). |
startDatePicker / endDatePicker |
DatePicker |
All-day pickers (hidden while timed). |
recurrencePicker |
RecurrencePicker | null |
The embedded Recurrence Picker. |
value |
ScheduleValue | null |
Current schedule; null when empty or invalid. |
validity |
SchedulePickerValidity |
{ valid, error, message }. |
timeZone |
string |
The timezone of the wall-clock times. |
name |
string | null |
Form field name. |
label |
string |
Legend text. |
disabled |
boolean |
Disabled state. |
dirty |
boolean |
The iCalendar text differs from the initial value. |
touched |
boolean |
Focus has left the control. |
options |
Readonly<SchedulePickerOptions> |
Current options. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
setValue(value: ScheduleValue | null): void |
Programmatic value (no events). |
update(options: Partial<SchedulePickerOptions>): void |
Merge and apply options (recurrence cannot change). |
reportValidity(): boolean |
Show messages now and return validity. |
setCustomError(message: string | null): void |
External error; cleared on the next edit. |
getFormValue(): string | null |
iCalendar text, or null. |
focus(): void |
Focus the start. |
reset(): void |
Restore the initial value. |
destroy(): void |
Remove rendering, inner pickers, listeners, and registration. |
scheduleToString(value: ScheduleValue): string; parseSchedule(text: string, disambiguation?: Disambiguation): ScheduleValue | null |
Module functions: iCalendar text of a schedule and back. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-change |
{ value: ScheduleValue | null; validity: SchedulePickerValidity } |
Yes | No | The user changed a part of the schedule or its validity error. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-field aui-schedule-picker | --invalid | --disabled | --all-day |
Host and state modifiers. |
aui-schedule-picker__fieldset | __range | __part | __part--start | --end | --start-date | --end-date |
Fieldset and picker hosts. |
aui-schedule-picker__duration |
Duration text (referenced by the fieldset). |
aui-schedule-picker__row | __row--zone | __check | __checkbox | __label | __select |
All-day checkbox and timezone select. |
aui-schedule-picker__recurrence |
Host of the embedded Recurrence Picker. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
error |
alert-circle |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-disabled-bg | --aui-color-error-fg | --aui-color-focus-ring | --aui-color-primary | --aui-color-surface | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-control-height-md | --aui-control-padding-x | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-weight-medium | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-space-1 | --aui-space-2 | --aui-space-3 | --aui-touch-target-min
TypeScript definitions
Section titled “TypeScript definitions”type ScheduleValue = | { allDay: false; start: Instant; end: Instant; timeZone: string; recurrence: RecurrenceRule | null } | { allDay: true; start: PlainDate; end: PlainDate; timeZone: string; recurrence: RecurrenceRule | null };type SchedulePickerError = 'value-missing' | 'incomplete' | 'invalid-start' | 'invalid-end' | 'end-before-start' | 'recurrence' | 'custom';interface SchedulePickerValidity { valid: boolean; error: SchedulePickerError | null; message: string }interface SchedulePickerChangeDetail { value: ScheduleValue | null; validity: SchedulePickerValidity }declare function scheduleToString(value: ScheduleValue): string;declare function parseSchedule(text: string, disambiguation?: Disambiguation): ScheduleValue | null;Accessibility
Section titled “Accessibility”Pattern: A fieldset composing labelled pickers (APG date picker dialogs), a native checkbox and select, and an optional Recurrence Picker fieldset.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Picker | Start, end (with their calendar buttons), all day, timezone, then the recurrence controls. |
| Picker keys | Start / end | As DateTime Picker and Date Picker (segments, ArrowUp/ArrowDown, calendar popup). |
| Space | All day | Toggles all-day; the pickers switch between times and dates. |
| Element | Role |
|---|---|
| fieldset | group (native) |
| start/end | DateTime Picker or Date Picker groups |
| all day | checkbox (native) |
| timezone | combobox (native select) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-describedby |
fieldset | Help text, error message, and the duration text |
label |
inner pickers | “Starts” / “Ends” (timed), “Start date” / “End date” (all-day) |
Hidden pickers (timed or all-day) are not focusable. Toggling all-day keeps focus on the checkbox.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- Moving the start moves the end by the same amount, so the duration is kept; the duration text is part of the description.
- Screen-reader behavior has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Behavior
Section titled “Behavior”States
Section titled “States”Timed, all-day, with timezone select, with recurrence, incomplete, end before start, disabled, required, invalid.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| timed | start changed | end moves by the same amount |
| timed | end changed | new duration (kept for later start changes) |
| timed | all day checked | days of the start and of the last moment |
| all-day | all day unchecked | previous start time (09:00 by default) and duration |
| any | timezone select | same wall-clock times in the new zone |
| any | one part empty, end not after start, inner or recurrence error | invalid (value null) |
Accessibility notes
Section titled “Accessibility notes”- Keeping the duration when the start moves avoids an extra correction step.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.
Responsive behavior
Section titled “Responsive behavior”Start and end sit side by side when there is room (auto-fit, 14rem minimum) and stack otherwise; reflows at 320 px.
Right-to-left
Section titled “Right-to-left”All parts follow direction.
Theming
Section titled “Theming”Inner pickers keep their styles; the timezone select uses the control surface; the recurrence section has a top border. Forced colors follow the inner pickers.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { schedulePicker: { defaultDuration: 30 } } });Global options: validationTiming, defaultDuration, plus inherited locale, timezone, disambiguation, direction.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults; recurrence is init-only.
Timezones
Section titled “Timezones”Timed values are exact Instants plus timeZone: the inner pickers show and parse wall-clock times in that zone (the value’s zone, else the select, else the timezone option; UTC unless configured) with the DST policy (disambiguation, compatible by default, section 8.5). A typed time in a DST gap is reported by the inner Date Input and resolved by the policy. Changing the zone keeps the wall-clock times (09:00 in London becomes 09:00 in New York). All-day values are dates. The recurrence expands in the schedule’s zone. In iCalendar text, timed values use TZID= and local times; all-day DTEND is the day after the last day (RFC 5545), while ScheduleValue.end is the last day.
error (alert-circle); inner pickers use their calendar icons.
Security
Section titled “Security”Text through textContent; timezone names from Intl. parseSchedule accepts a strict subset and returns null otherwise.
Data handling
Section titled “Data handling”No persistence or network access. One hidden input with the iCalendar text when name is set; inner pickers are not form controls.
Performance
Section titled “Performance”Creates four inner pickers (two hidden) and, with recurrence, a Recurrence Picker. Budget (e2e): create with recurrence < 30 ms per instance.
Supported data scale
Section titled “Supported data scale”One schedule per instance.
Edge cases
Section titled “Edge cases”- An end equal to the start is invalid for timed schedules; for all-day schedules start and end may be the same day.
- A timed end at midnight belongs to the previous day when switching to all-day.
- A value whose
timeZoneis not intimeZonesis added to the select. parseSchedulerejects floating times (no TZID or Z) and all-day DTEND on or before DTSTART.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
SCHEDULE_PICKER_OPTIONS |
configuration | Empty label; invalid value (kinds, end, timeZone); invalid timeZones, booleans, callbacks, config; changing recurrence after creation. |
UI validation errors: value-missing, incomplete, invalid-start, invalid-end, end-before-start, recurrence, custom.
Known limitations
Section titled “Known limitations”- One timezone for start and end.
- No separate duration field.
- Manual screen-reader verification is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- Floating times; several ranges in one value.