Usage
EventRecurrencePicker from @prepared911/ui-calendar lets operators configure a repeating schedule in one place. It composes frequency selection, optional custom cadence, start date and time, end rules, and an always-visible summary line—so an operator defining "weekdays 9am to 5pm until Dec 31" sees the whole rule rather than piecing it together from four separate inputs. The committed value is an EventRecurrencePickerValue; getRecurrenceSummary(value) renders the same prose the picker shows internally.
Today this is primarily the non-emergency intent scheduler—see manage-nonemergency/Intents/IntentModal/components/CreateSchedulePopover.tsx and ConfiguredScheduleEntry.tsx for the two canonical call sites.
–
America/New_York
Weekly
Repeats weekly, starting April 20, 2026 · 09:00–17:00.
Badge (see ConfiguredScheduleEntry), getRecurrenceSummary gives operators and reviewers the same prose.DateTimePicker. The recurrence machinery is overhead.AdvancedDateRangePicker or AdvancedDateTimeRangePicker; recurrence does not apply to search or analytics filters.DateTimePicker or DatePicker with a note; recurrence is for the rule, not individual events.The picker renders three conceptual groups inside a single panel, with animated transitions when the operator enters a custom cadence:
Combobox over the RecurrenceFrequency enum: Daily, Weekdays, Weekends, Weekly, EveryTwoWeeks, Monthly, MonthlyNthDay, Annually, Custom.Custom). A nested group of Switch, Combobox, and selectors—CustomRecurrenceOptions—that expands into CustomRecurrenceType plus monthly-mode and weekday selectors as needed.DatePicker, start / end times via TimeRangePicker, plus an All-day Switch.RecurrenceEndType: Never, On (a committed end date), or After (a count of occurrences).getRecurrenceSummary renders the full rule in plain English above or below the body, depending on your layout, so operators see what they're committing.cta adds Reset / Apply; pairing trigger with cta and open / onOpenChange turns the whole control into a popover (see CreateSchedulePopover).
getRecurrenceSummary(value) drive any echoed chip or description: don't reformat the rule yourself.09:00 and end time to 17:00. If your product has different business hours, pass a seeded value rather than expecting operators to reset.cta + trigger. When both are set, the picker tracks in-progress changes internally and only emits onChange when Apply fires: so closing the popover via Escape or outside-click discards the draft, matching the modal-commit expectation.getRecurrenceSummary so the rule text stays accurate without an Apply step.Custom slides the custom pane in; switching away slides it out. Focus stays on the operator's most recent control.disabled cascades to every sub-control so a parent "view only" state doesn't let part of the rule stay editable.value with the product's default start / end times and timezone (getSystemTimezone() is the shipped default).disableFuture. Prevents selecting a future start date; useful when the series must begin today or earlier.trigger + open + onOpenChange. Use for popover-driven entry; leave them off for inline panels.cta. Required when you want deferred commits. Without it, every change dispatches: acceptable in a dedicated form but not in a popover.Do
getRecurrenceSummary(value) in any committed chip or summary: keeping two copies of the prose in sync by hand is a bug farm.cta with a popover via trigger + open so closing discards the draft.EventRecurrencePicker instance per rule; if you need two rules, render two pickers, not a multi-select.Don't
The picker chains multiple sub-controls (Combobox, Switch, DatePicker, TimeRangePicker). Tab order, focus on open, and announcing the summary on changes are part of the app's responsibility; the picker supplies the visible prose and the draft-commit discipline. See the Accessibility page for the full contract, including the aria-live pattern for the summary.