Skip to content
SuperCoach

Components · Inputs

Date picker

Beta

Picks a date, such as a program start date.

Week 1 of the program starts on this day.

When to use

  • For a date field in a form: a program start date, a session date, a payment due date.
  • For a date range in a toolbar or a filter: the period of a check-in or revenue report.

When not to use

  • When the calendar is the main content of the view: show a Calendar inline.
  • For a date of birth or other dates years away: use the calendar's month and year menus, or three inputs.
  • For a time of day: there is no time picker yet; use an Input or a Select of time slots.

Anatomy

  1. 1. Label: always visible, above the trigger
  2. 2. Trigger: an outline button that opens the calendar
  3. 3. Calendar icon, at the start
  4. 4. Value: the chosen date, or a placeholder

A date picker is a composition, as in shadcn's date picker recipe: a Button as the trigger, a Popover, and a Calendar inside it. Open the example to see the popover: the calendar with its month caption, month buttons and day grid, aligned to the trigger's start edge. Picking a day closes the popover and writes the date into the trigger.

Variants

  • Single date: the default above. The popover closes on select.
  • Range: mode="range" with two months side by side. The popover stays open until the coach clicks outside or presses Escape, so both ends can be picked. The trigger shows "2 Nov – 15 Nov 2026".
  • With presets: coach-admin's report filters offer "Last 7 days", "This month" next to the calendar. Put them as buttons above the calendar inside the popover.

States

The program has started.

Pick a start date to send the program.

StateWhat changesToken
PlaceholderLighter texttext-muted-foreground
Hover (trigger)Accent fillbg-accent, text-accent-foreground
Focus-visible (trigger)Border and a 3px ringborder-ring, ring-ring/50
OpenPopover with border and shadow, on the popover layerbg-popover, shadow-md, z-(--z-popover)
DisabledHalf opacity, no pointer eventsopacity-(--opacity-disabled)
InvalidRed border and ring, error text belowborder-destructive, ring-destructive/20, text-destructive-text

Day states inside the popover (today, selected, range, disabled) are listed on the Calendar page.

Usage guidelines

Do.A visible label and the date written out, so it can't be misread.
Don't.A trigger with no label and a vague placeholder. The coach can't tell which date this is.
  • Disable dates that can't be picked, such as past dates for a program start (disabled={{ before: new Date() }}), and say why in help text if it isn't obvious.
  • Open the calendar on the month of the current value, or on today when empty.
  • Close the popover on select for single dates. Move focus back to the trigger, which Radix does on close.
  • Show the error after the popover closes without a date, not while the coach is still choosing.

Content guidelines

  • Label: what the date is for: "Program start date", "Report period". Not "Date".
  • Placeholder: "Pick a date" or "Pick a date range".
  • Value: the Content format: "2 Nov 2026"; ranges "2 Nov – 15 Nov 2026". In Arabic: "2 نوفمبر 2026", with Western digits.
  • Help text says what happens on that date: "Week 1 of the program starts on this day."

Accessibility

KeyDoes
Enter, Space (on the trigger)Opens the calendar; focus moves to the selected day, or today
Arrow keys, Page up / downMove through days and months, as on the Calendar
Enter, Space (on a day)Selects it; a single date picker closes and focus returns to the trigger
EscapeCloses without changing the value; focus returns to the trigger
  • The trigger is a button with aria-haspopup="dialog" and aria-expanded, from the Radix popover. It is labelled by both the label and the current value (aria-labelledby lists the two ids), so a screen reader announces "Program start date 2 Nov 2026, button, collapsed". Without that, the label replaces the button text and the date is never read.
  • Help and error text are linked with aria-describedby; an invalid trigger has aria-invalid="true".
  • autoFocus on the calendar moves focus into the grid when the popover opens.

RTL

  • The calendar icon is at the start of the trigger, on the right in RTL. It doesn't mirror.
  • The popover aligns to the trigger's start edge (align="start"), its right edge in RTL.
  • Inside the popover, the calendar mirrors as described on the Calendar page: weeks run right to left and the month chevrons point outwards.
  • Pass locale={lang === "ar" ? ar : enUS} from react-day-picker/locale and numerals="latn", and format the trigger's value with the same locale.

Tokens used

The trigger is an outline Button and the panel a Popover. The calendar inside reads:

Read from components/ui/calendar.tsx at build time, so this list changes when the component does. Opacity modifiers such as /90 are shadcn hover and focus tints on top of the token.

Semantic color tokens used by this component
TokenUtilitiesSuperCoachCoach
--accentbg-accentbrand-50orange-50
--accent-foregroundtext-accent-foregroundbrand-700orange-700
--backgroundbg-backgroundwhitewhite
--inputborder-inputneutral-200neutral-200
--muted-foregroundtext-muted-foregroundneutral-600neutral-600
--popoverbg-popoverwhitewhite
--primarybg-primarybrand-600orange-500
--primary-foregroundtext-primary-foregroundwhitewhite
--ringborder-ring ring-ring/50brand-600orange-500
  • Layerz-(--z-raised)
  • Opacityopacity-(--opacity-disabled)
  • Radiusrounded-md rounded-e-md rounded-s-md
  • Radiusrounded-none
  • Shadowshadow-xs
  • Typefont-medium
  • Typeleading-none
  • Typefont-regular
  • Typetext-sm
  • Typetext-xs

Props

The date picker has no component of its own. These are the Calendar props; see Popover for the popover parts.

<Calendar>

Also takes every prop of <DayPicker>

Calendar props
PropTypeDefault
buttonVariant?React.ComponentProps<typeof Button>["variant"]"ghost"

<CalendarDayButton>

Also takes every prop of <DayButton>

No props of its own.

Replaces in coach-admin

From the read-only audit of coach-admin: 41 style values, 47 uses.

coach-admin has a date range picker with presets (date-range-picker) and a separate one in the finance pages (finance-date-range-picker). Both become this component in range mode.

Classes and selectors

  • .date-range-picker__input4
  • .datefilter4
  • .date-range-picker__presets4
  • .finance-date-range-picker__trigger3
  • .finance-date-range-picker__dropdown3
  • .date-range-picker__dropdown3
  • .date-range-picker__required2
  • .date-range-picker__icon1
  • .date-range-picker__arrow1
  • .date-range-picker-button .apply-btn-container1
  • .finance-date-range-picker__list1
  • .date-range-picker__dropdown--with-presets1

Files

  • src/reusableComponents/formComponents/date-range-picker/date-range-picker.scss32

The inventory lists the first 12 locations of each value, so file counts are a lower bound.

SCSS variables in these styles

  • $input-border-colornot a color: spacing, size or layout
  • $input-focus-shadownot a color: spacing, size or layout
  • $card-surface-bgnot a color: spacing, size or layout
  • $error-color→ --destructive
  • $input-placeholder-color→ nearest neutral-300 (no semantic token)
  • $input-affix-color→ nearest neutral-400 (no semantic token)
  • $border-color→ --border
  • $input-shadownot a color: spacing, size or layout
  • $dropdown-panel-shadownot a color: spacing, size or layout
  • $z-index-dropdownnot a color: spacing, size or layout

Calendar, Popover, Input, Form.