Deck
Browse the catalog

Build / Molecules

DayStrip

  • molecule

Horizontal day picker for a booking flow's availability step.

Each day carries how many slots are free, so the choice is informed before it is made — a day with two openings looks different from one with twelve, and a full day is disabled rather than a dead end. Month changes are labelled inline so a strip spanning a boundary stays legible.

Renders as a radio group: arrow keys move along the strip, and the selection is announced with its date and availability.

import { DayStrip } from '@meetcard/deck'

Example

<DayStrip value={day} onChange={setDay} today="2026-09-01" timeZone="America/Denver" days={[ { date: '2026-09-01', slotCount: 6 }, { date: '2026-09-02', slotCount: 0 }, ]} />

Stories

Every preview below is the real component, rendered in this page from the same story Storybook runs. The width control resizes each preview's container; CSS media queries still follow the browser window, so breakpoint behaviour is worth checking in Storybook.

Default
Source
const Default = args => {
    const [value, setValue] = useState(args.value)

    return (
        <DayStrip
            today="2026-09-01"
            timeZone="America/Denver"
            days={[
              { date: '2026-09-01', slotCount: 2 },
              { date: '2026-09-02', slotCount: 6 },
              { date: '2026-09-03', slotCount: 9 },
              { date: '2026-09-04', slotCount: 4 },
              { date: '2026-09-05', slotCount: 0 },
              { date: '2026-09-08', slotCount: 7 },
              { date: '2026-09-09', slotCount: 1 },
            ]}
            value={value}
            onChange={setValue} />
    );
};

A day chosen. The selection is announced with its date and how many slots it has.

Selected
Source
const Selected = args => {
    const [value, setValue] = useState(args.value)

    return (
        <DayStrip
            today="2026-09-01"
            timeZone="America/Denver"
            days={[
              { date: '2026-09-01', slotCount: 2 },
              { date: '2026-09-02', slotCount: 6 },
              { date: '2026-09-03', slotCount: 9 },
              { date: '2026-09-04', slotCount: 4 },
              { date: '2026-09-05', slotCount: 0 },
              { date: '2026-09-08', slotCount: 7 },
              { date: '2026-09-09', slotCount: 1 },
            ]}
            value={value}
            onChange={setValue} />
    );
};

Days with no openings are disabled rather than left as a dead end.

Fully Booked
Source
const FullyBooked = args => {
    const [value, setValue] = useState(args.value)

    return (
        <DayStrip
            today="2026-09-01"
            timeZone="America/Denver"
            days={[
              { date: '2026-09-01', slotCount: 0 },
              { date: '2026-09-02', slotCount: 0 },
              { date: '2026-09-03', slotCount: 3 },
            ]}
            value={value}
            onChange={setValue} />
    );
};

The month is re-labelled wherever the strip crosses a boundary.

Across Months
Source
const AcrossMonths = args => {
    const [value, setValue] = useState(args.value)

    return (
        <DayStrip
            today="2026-08-30"
            timeZone="America/Denver"
            days={[
              { date: '2026-08-30', slotCount: 3 },
              { date: '2026-08-31', slotCount: 5 },
              { date: '2026-09-01', slotCount: 2 },
              { date: '2026-09-02', slotCount: 8 },
            ]}
            value={value}
            onChange={setValue} />
    );
};

Props

PropTypeDefaultDescription
daysrequiredDayOption[]——
classNamestring——
labelstring'Pick a day'—
localestring——
onChange(date: string) => void——
timeZonestring—IANA zone the days are expressed in, shown alongside the label.
todaystring—ISO date rendered with a "Today" marker.
valuestring—ISO date of the selected day.

Open in Storybookfor controls, the a11y panel and the interaction runner.