Prepared Docs

Prepared Docs

⌘K

    Loading navigation…

User

  1. Calendar
  2. Event Recurrence Picker
  3. Usage

Event Recurrence Picker

Usage

Overview

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.

When to use

  • Repeating schedules. On-call rotations, recurring availability windows, and intent schedules all need frequency + end rule + start anchor together; a flat form buries the rule.
  • Surfaces that show a summary chip. When the committed rule is echoed as a Badge (see ConfiguredScheduleEntry), getRecurrenceSummary gives operators and reviewers the same prose.
  • Multi-rule compositions. When an operator configures two or more overlapping schedules, each instance of the picker keeps its rule contained and editable in place.

When not to use

  • One-off date + time. Use DateTimePicker. The recurrence machinery is overhead.
  • Calendar-bound filters. Use AdvancedDateRangePicker or AdvancedDateTimeRangePicker; recurrence does not apply to search or analytics filters.
  • Ad-hoc instances of a series. Use a separate DateTimePicker or DatePicker with a note; recurrence is for the rule, not individual events.

Composition

The picker renders three conceptual groups inside a single panel, with animated transitions when the operator enters a custom cadence:

  • Frequency. A Combobox over the RecurrenceFrequency enum: Daily, Weekdays, Weekends, Weekly, EveryTwoWeeks, Monthly, MonthlyNthDay, Annually, Custom.
  • Custom options (when Custom). A nested group of Switch, Combobox, and selectors—CustomRecurrenceOptions—that expands into CustomRecurrenceType plus monthly-mode and weekday selectors as needed.
  • Schedule body. Start date via DatePicker, start / end times via TimeRangePicker, plus an All-day Switch.
  • End rule. RecurrenceEndType: Never, On (a committed end date), or After (a count of occurrences).
  • Summary line. 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).

Content guidelines

  • Summary copy is the source of truth. Let getRecurrenceSummary(value) drive any echoed chip or description: don't reformat the rule yourself.
  • Sensible defaults. Start time defaults to 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.
  • End on vs end after. "End on Dec 31" is clearer for fixed-term rotations; "end after 10 occurrences" is clearer for limited runs. Pick the default that matches your most common case.
  • Write for reviewers. The summary is often displayed to someone other than the author (audit logs, approval surfaces): keep product-side labels concrete ("Schedule:", not "Config:").

Behavior and states

  • Draft-only state for 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.
  • Summary updates in place. Every sub-control change recomputes getRecurrenceSummary so the rule text stays accurate without an Apply step.
  • Custom cadence animation. Switching Frequency to Custom slides the custom pane in; switching away slides it out. Focus stays on the operator's most recent control.
  • Disabled cascading. disabled cascades to every sub-control so a parent "view only" state doesn't let part of the rule stay editable.

Customization

  • Start and end defaults. Pass a seeded 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.

Best practices

Do

  • Echo getRecurrenceSummary(value) in any committed chip or summary: keeping two copies of the prose in sync by hand is a bug farm.
  • Pair cta with a popover via trigger + open so closing discards the draft.
  • Align default start / end times with organizational business hours and document the assumption in surrounding help text.
  • Keep one EventRecurrencePicker instance per rule; if you need two rules, render two pickers, not a multi-select.

Don't

  • Don't recreate the rule with individual form fields when a rule is repeating: operators lose the summary and the validation that comes with the picker.
  • Don't bind the picker's internal draft to filter state: it's a committed rule, not an incremental query.
  • Don't hide the summary line to save space: it is the only plain-English view of the rule.

Accessibility

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.

Related

  • Date Picker: the calendar grid embedded in the schedule body.
  • Date Time Picker: one-off date + time without recurrence.
  • Time Picker: the time input used inside the range.

Previous

Date Time Picker / Accessibility

Next

Event Recurrence Picker / API and Development

On this page

Overview
When to use
When not to use
Composition
Content guidelines
Behavior and states
Customization
Best practices
Accessibility
Related