Prepared Docs

Prepared Docs

⌘K

    Loading navigation…

User

  1. Calendar
  2. Event Recurrence Picker
  3. Accessibility

Event Recurrence Picker

Accessibility

Overview

EventRecurrencePicker composes a Combobox for frequency, a nested CustomRecurrenceOptions group for custom cadences, a DatePicker for the start anchor, a TimeRangePicker for start and end times, a Switch for All-day, and end-rule selectors. Each sub-control carries its own @prepared911/ui-core accessibility guarantees; the picker wires them into one panel. The app owns the accessible name for the whole control, announcing the getRecurrenceSummary prose, and the focus handoff into a surrounding Popover when trigger is used.

What the component handles

  • Sub-control semantics. Every sub-control (Combobox, Switch, DatePicker, TimeRangePicker, Input, Label) is a Prepared-shipped component with its own a11y story: labels, keyboard handling, and focus styling.
  • Animated pane transitions. Switching frequency to Custom slides in the custom pane; focus stays on the operator's most recent control and does not get stolen by the animation.
  • Draft state for popover use. When cta + trigger are set, the picker holds draft changes internally and only emits onChange when Apply fires: so closing the popover via Escape discards the draft without committing.
  • Disabled cascade. disabled passes down to every sub-control so a parent "view only" state doesn't leave part of the rule editable.
  • Summary prose. getRecurrenceSummary(value) returns the same plain-English rule the picker shows; use it for live regions and echoed chips.

What you must provide

  • Accessible name for the control group. Wrap the picker in role="group" with aria-labelledby pointing at a visible heading (e.g. "Schedule"), or aria-label if no heading exists.
  • Trigger accessible name. When trigger is set, the trigger element owns its accessible name; icon-only triggers need aria-label.
  • Visible summary or live region. getRecurrenceSummary returns the prose; render it as visible text or pipe it into a polite live region so the committed rule is heard on change.
  • Section headings. Keep a clear visible hierarchy between Frequency, Start, and End rule so screen reader users can navigate the panel by headings.
  • Focus on open. When hosting the picker in a popover, focus the frequency Combobox (or your preferred entry point) when the popover opens so keyboard users land inside the panel.

Keyboard behavior

  • Tab / Shift+Tab moves through Frequency → (custom pane, if active) → Start date → All-day Switch → Time range → End rule → Apply / Reset in visual order.
  • Arrow keys inside Comboboxs move between options; Enter or Space commits the focused option; Escape closes the combobox without committing.
  • Arrow keys inside the start DatePicker match DatePicker: Up / Down by week, Left / Right by day.
  • Space toggles the All-day Switch.
  • Enter / Space activates Apply / Reset and the hosting popover's trigger.
  • Escape closes a focused combobox; at the outer level, closes the hosting popover (discarding the draft when cta + trigger are set).

Semantics and roles

  • Root wrapper. No landmark by default; wrap it in role="group" with a name.
  • Frequency selector. Combobox from @prepared911/ui-core (Radix-backed) with aria-expanded and aria-controls.
  • Custom pane. A nested FlexBox with Combobox and selectors; each selector owns its own semantics.
  • Start / time / end controls. Each composes its own underlying @prepared911/ui-core primitive with its own roles and labels.
  • Apply / Reset. Native <button> via @prepared911/ui-core Button.

Focus management

Opening a popover-hosted picker should place focus inside the panel—typically the frequency Combobox—so keyboard operators don't land on the trigger only to need another Tab. Closing should restore focus to the trigger. When the operator enters the custom pane, keep focus on the most recent control they were on; animated transitions should not steal focus.

Screen reader announcements

The picker does not announce getRecurrenceSummary updates by itself. Route the prose through a polite live region (as in the example above) so the rule is heard after every committed sub-control change. Keep the announcement brief—it should reflect the committed rule, not every intermediate keystroke inside a draft popover.

When operators switch Frequency to Custom, the sliding animation does not announce the pane change; a short heading inside the custom pane ("Custom cadence") read by screen readers as focus moves in is sufficient.

Known caveats

  • Motion. The custom-pane transition uses @prepared911/ui-core animation helpers. The component does not currently consult prefers-reduced-motion; match whatever the surrounding surface already does for reduced motion.
  • Sub-controls rely on their own accessibility contracts. Issues surfaced inside Combobox, DatePicker, or Switch show up here, too: validate against those components' individual guidance.
  • Draft vs committed. When cta is false, every sub-control change emits onChange. Surfaces that rely on draft-only behavior should always pair cta with trigger.
  • Timezone is implicit. The committed value includes a timezone string; if your app displays times in a different zone, surface the source zone in visible copy.

Previous

Event Recurrence Picker / API and Development

Next

Advanced Date Range Picker / Usage

On this page

Overview
What the component handles
What you must provide
Keyboard behavior
Semantics and roles
Focus management
Screen reader announcements
Known caveats