Date picker
Takes a date, or a range of dates, typed as mm/dd/yyyy or picked from a calendar. Use Simple date where the reader knows the date already, and a calendar where they need to browse for it.
Live preview
Rendered by the component itself from the same generated tokens as the rest of the site.
const [value, setValue] = useState<Date | null>(null)
<DatePicker
label="Date"
value={value}
onChange={setValue}
/>Installation
Install it with the shadcn CLI, along with everything it uses. New project? Set it up first, as Quick start shows.
npx shadcn@latest add https://www.graphite-ui.com/r/date-picker.jsonimport { DatePicker } from '@/components/ui/date-picker'Anatomy
The label, then the field with the date typed as mm/dd/yyyy and the calendar button at its end. The button opens the calendar under the field: the month with previous and next, the weekdays, and six weeks of days, today marked with a dot.
- FieldRequiredThe governed Text input, typed as mm/dd/yyyy (the kit's placeholder). One for Simple and Single, two for a Range (start and end, each labelled). Fixed or Fluid.
- Calendar triggerOptionalThe kit's 16px fi-rs-calendar at the end of the field, a button that opens the calendar. Single and Range only; Error and Warning swap it for the status glyph, as the kit draws them.
- CalendarOptionalThe kit's private _Date picker calendar, under the field. 288 wide on elevation-01 with the overlay shadow, padded 4 4 8 4. A 40 header (previous, month and year, next), the weekday row, and six rows of 40 × 40 days.
- Supporting textOptionalHelp, error or warning text; under a Range's two fields together.
Variants
Simple date is the field alone. Single calendar adds the calendar. Range calendar has a start and an end field over one calendar. Each comes in Default, at 48, 40 or 32, and in Fluid, a 64px box with the label inside.
States
The field’s states are Text input’s: a 2px ring on focus, the danger ring and glyph for an error, the warning glyph, the disabled and read-only shells. Error and warning take the calendar button’s place with the status glyph, as the kit draws them.
API reference
Generated from the contract, versioned with it, and checked by drift-check. This table cannot describe props the component does not have.
| Prop | Type | Default | Notes |
|---|---|---|---|
| mode | 'simple' | 'single' | 'range' | — | The kit's Simple date, Single calendar and Range calendar sets. Single by default. |
| layout | 'fixed' | 'fluid' | — | The kit's Default and Fluid sets. A Fluid range joins its two boxes with a 1px outline-strong rule. |
| size | 'sm' | 'md' | 'lg' | — | Fixed only, the Text input heights 32, 40 and 48. Large by default, as the kit's sets are. |
| value / onChange | — | — | Controlled. A date or null; for a range, a start and end pair. Typing commits on Enter or on leaving the field; a half-typed date stays as typed for the caller to flag. |
| label / endLabel | — | — | The label is required; endLabel names a range's end field ("End date" by default). |
| minDate / maxDate | — | — | Days outside are disabled in the calendar. |
| helpText / errorText / warningText | — | — | Through the shared field-message rule. |
| disabled | boolean | — | |
| readOnly | boolean | — | The field's Read-only shell; the calendar glyph stays as a mark and does not open. |
Design tokens
Every swatch is live. Change the source color in the header and this table repaints, because it reads the same roles the component does.
elevationThe calendar panel, elevation-01 (Layer/layer-01); header and day hover and the year box while edited, elevation-02 (Layer/layer-hover-01).shadowThe calendar's overlay shadow (Shadows/Menu).on-surfaceThe calendar glyph, the month, year, weekdays and days (Icon/icon-primary, Text/text-primary).on-surface-variantDays of the months either side (Text/text-secondary).primaryThe selected day's fill (Button/button-primary), today's number and dot (Miscellaneous/interactive), the focus ring through primary-focus, and disabled days through primary-disabled-content.on-primaryThe selected day's number (Text/text-on-color).primary-containerDays inside a range (Miscellaneous/highlight).outlineA Fluid range's dividing rule, through the strong step (Border/border-strong-01).dangerA range's error text.textBody/3 for days and weekdays, Title/5 for the month, year and today, Caption/1 for supporting text.spacingThe panel's padding and gaps.
Usage
The contract's prohibitions, written as the choices you will actually face.
Do
- Show the format: the placeholder does until the reader types, so put it in the label for Simple date.
- Use a calendar where the day of the week or the month around it matters.
- Use Range calendar for a start and an end, so the two share one calendar.
- Set minDate and maxDate to keep the reader inside the dates that are allowed.
Don’t
- Build a range from two single pickers.
- Use a calendar for a date of birth. The reader knows it; Simple date is faster.
- Hide the field. Typing is often quicker than the calendar.
- Restyle the fields. They are the governed Text input.
Accessibility
What the component does for you, and what it leaves to you.
- Roles
- The field is a labelled text input; the calendar button has
aria-haspopup="dialog"andaria-expanded. The calendar is a dialog holding agrid, each day a button named in full (“Wednesday, October 14, 2026”), today witharia-current="date". - Keyboard
- Arrow Down in the field, or the button, opens the calendar on the selected day. Arrows move by day and week, Home and End to the week’s ends, Page Up and Page Down by month, with Shift by year. Enter picks; Escape closes and returns to the button.
- Typing
- Enter or leaving the field commits a date typed as mm/dd/yyyy. Anything else stays as typed, for the page to flag with errorText.
- Focus
- Days and the month buttons take a 2px
--graphite-primary-focusring inside; the field takes Text input’s. - Range
- The two fields form a labelled group. The calendar picks the start, then the end; an end before the start swaps them.
Figma parity
The kit’s Date picker page has eleven public sets. Six are the date pickers, Default and Fluid for each of three kinds; the code is one component with a mode and a layout. The Time picker sets on the same page are their own component.
| Kit axis | Values | Code | How it maps |
|---|---|---|---|
| Set | Simple date · Single calendar · Range calendar | mode | simple, single, range. |
| Set | Default · Fluid | layout | Text input’s fixed and fluid layouts. |
| Size | Large · Medium · Small | size | 48, 40 and 32, the Text input heights. The kit’s Simple date also lists Fluid Input as a size; that is the Fluid layout. |
| State | Enabled · Hover · Focus · Active | — | Focus is the field’s; the kit draws Hover as Enabled. Active is the field with the calendar in use. |
| State | Open · Focus + Open · Active + Open | — | The calendar is open. |
| State | Error · Warning · Disabled · Read-only | errorText, warningText, disabled, readOnly | Error and Warning swap the calendar glyph for the status glyph. |
| State | Skeleton | — | No counterpart by rule. |
| Day item | Enabled · Hover · Focus · Selected · Today · Day in range · End range hover · Prev/Next month · Disabled | — | Drawn from the date, the selection and the pointer. |
| Placeholder | text-helper · text-placeholder | — | The kit uses two colours across the sets; the code uses the field shell’s one. |
| Fluid label | Tooltip trigger | — | Not drawn: Text input’s Fluid label stands alone. |
