components / datepicker

DatePicker

Single-date field and calendar surface with blocked dates, honest keyboard travel, and date-only values.

Overview

What it is

This section explains the intent of the component before the implementation details.

  • DatePicker turns the DK field shell into a single-date chooser with a real popover calendar and keyboard model.
  • It is intentionally date-only in v1 so selection stays predictable and testable.

Decision guide

How to choose it

Use these notes to decide quickly whether this is the right DK component for the job.

Decision guide

  • Choose DatePicker when the interaction should feel deliberate, documented, and reusable across product surfaces.
  • If the scenario is more specialized than the current DatePicker contract, prefer a simpler component or build a dedicated workflow on top of the lower-level DK primitives.

Do

  • Keep the DatePicker label, value, or status language direct enough to scan quickly.
  • Use the documented size and state recipes instead of inventing one-off variants in product code.

Do not

  • Do not hide the main purpose of DatePicker behind decorative copy or overloaded surface treatments.
  • Do not stretch DatePicker into a workflow it was not designed to handle just because the visuals are close.

Usage

When to use

Prefer these situations when choosing this component.

  • Use DatePicker when users need help choosing a calendar date rather than typing one from memory.
  • Use min, max, and blocked dates when the workflow has real scheduling constraints.

Usage

When not to use

These patterns are better served by a different component or a simpler surface.

  • Do not use DatePicker for ranges, times, or multi-month planning in this v1 contract.
  • Do not silently coerce timezone-heavy timestamps into the component; it expects date-only values.

Anti-patterns

  • Using DatePicker as a generic layout container instead of a purpose-built interaction or content surface.
  • Forking the documented recipe in product code instead of extending the shared DK contract.

Migration notes

  • Migrate legacy datepicker usage by mapping existing variants and states onto the documented DK props before porting any custom styling.
  • Treat the docs examples as the reference contract for accessibility and event behavior during adoption.

Anatomy

Structural parts

The anatomy explains which pieces matter to the recipe and accessibility model.

field wrapper

root

Provides the field label, helper text, and validation state.

field button

trigger

Opens the calendar surface and displays the chosen date.

date grid surface

calendar

Anchored calendar surface with month navigation.

grid cell button

day

Selectable calendar day with range and disabled rules.

API

Public interface

The docs contract distinguishes props, DOM events, and slots so integration behavior is explicit.

Props

NameTypeDefaultDescription
labelstringVisible label used for the field or control.
descriptionstringSupporting helper copy rendered below or beside the main label.
errorstringValidation or problem copy rendered in the error slot when present.
placeholderstringPlaceholder text shown before a user makes a selection or enters text.
requiredbooleanfalseMarks the field or control as required for form semantics and docs examples.
disabledbooleanfalseDisables interaction and exposes the correct non-interactive semantics for the control.
namestringForm field name used for native form submission.
idstringOptional id used to bind external labels or descriptions to the component.
size'sm' | 'md' | 'lg''md'Chooses the compiled size recipe for the component.
valuestringControlled date-only value in `YYYY-MM-DD` format.
minstringMinimum selectable date in `YYYY-MM-DD` format.
maxstringMaximum selectable date in `YYYY-MM-DD` format.
disabledDatesstring[]Explicitly blocked date-only values.
weekStartsOn0 | 10Chooses Sunday or Monday as the first day of the week.
onChange(detail: { value: string | undefined }) => voidCallback fired when a valid date is selected.
themeThemeContractOverrides the compiled DK theme used to resolve tokens and recipes for this component.

Events

NamePayloadDescription
change{ value: string | undefined }Fires when the component commits a new value.

Slots

NameDescription
defaultDatePicker is prop-driven in v1 and does not expose custom slots.

Recipes

Variants, sizes, and states

These notes summarize the intended recipe surface rather than exposing raw implementation detail first.

Variants

  • default: DatePicker uses one single-date shell and varies by size.

Sizes

  • sm: Compact date field for dense tools.
  • md: Default date field size.
  • lg: Larger date field for touch-friendly surfaces.

States

  • closed: Date field is idle and the calendar is hidden.
  • open: Calendar surface is visible.
  • selected: A date has been committed to the field.
  • disabled: Date field cannot open or change.
  • blocked: Specific days cannot be selected due to range or explicit block rules.

Accessibility

Accessibility contract

This is the behavior the component promises to assistive tech and keyboard users today.

Semantics

  • Uses standard field labeling through visible labels, descriptions, and error text.
  • Exposes disabled and required semantics through the underlying form control.
  • Uses a labeled trigger button paired with an anchored date grid surface.

Keyboard

  • Supports native focus and text entry behavior.
  • Arrow keys move day focus, Home and End move within a week, and PageUp/PageDown change month.
  • Enter or Space selects the focused valid day and Escape closes the surface.

Screen readers

  • Connects visible label, helper text, and error text to the native control.
  • The trigger exposes the current selected date and the calendar surface announces the active month and focused day.

Caveats

  • DatePicker uses date-only values (`YYYY-MM-DD`) and intentionally avoids timestamp semantics in v1.

Checklist

  • Verify the visible label or title still produces a clear accessible name.
  • Verify focus remains obvious in every supported state and size.
  • Verify disabled, selected, and error states do not rely on color alone.

Implementation

Tokens and slot vars

This section shows the representative compiled slot variables that the runtime consumes for the selected design system.

root

--dk-field-stack-gap
0.45rem
--dk-date-picker-offset
8px
--dk-motion-duration
200ms

label

--dk-field-label-color
#16181c
--dk-field-label-size
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-field-label-weight
600

trigger

--dk-date-picker-trigger-bg
#f2f5fb
--dk-date-picker-trigger-fg
#16181c
--dk-date-picker-trigger-border
#95989d
--dk-date-picker-trigger-radius
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)
--dk-date-picker-trigger-block-size
48px
--dk-date-picker-trigger-inline-padding
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-date-picker-trigger-font-size
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)

icon

--dk-date-picker-icon-size
1rem
--dk-date-picker-icon-color
#16181c

description

--dk-field-description-color
#16181c
--dk-field-description-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

error

--dk-field-error-color
#cc272e
--dk-field-error-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

surface

--dk-date-picker-surface-bg
#f2f5fb
--dk-date-picker-surface-fg
#16181c
--dk-date-picker-surface-border
#95989d
--dk-date-picker-surface-radius
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-date-picker-surface-shadow
0 10px 15px rgba(0, 0, 0, 0.06), 0 4px 6px rgba(0, 0, 0, 0.04)
--dk-date-picker-surface-width
320px
--dk-date-picker-surface-padding
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)

caption

--dk-date-picker-caption-color
#16181c
--dk-date-picker-caption-size
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-date-picker-caption-weight
700

navButton

--dk-date-picker-nav-bg
#e5e8ed
--dk-date-picker-nav-fg
#16181c
--dk-date-picker-nav-size
36px

weekday

--dk-date-picker-weekday-color
#16181c
--dk-date-picker-weekday-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

day

--dk-date-picker-day-bg
#f2f5fb
--dk-date-picker-day-fg
#16181c
--dk-date-picker-day-radius
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)
--dk-date-picker-day-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)
--dk-date-picker-day-target
44px
--dk-date-picker-day-today-ring
#2072e4
--dk-date-picker-day-disabled-fg
#16181c
--dk-date-picker-day-outside-fg
#95989d

Implementation notes

  • DatePicker is intentionally single-date and date-only; range and time picking belong to a future contract.

Implementation checklist

  • Use the public component API first and only drop to lower-level primitives when the component contract genuinely does not fit.
  • Keep theme overrides token-driven so proofs and recipes stay meaningful.
  • Verify the shipped examples and proof fixtures still represent the real product scenario you are implementing.

Examples

Copy-paste examples

Each example is intentionally practical, grouped by starter, common pattern, and edge-case coverage.

Examples
3
Depth
expanded

Starter

1 example

starter

Starter: choose one launch date

A standard single-date field with a selected value.

Copy snippet

<DatePicker label="Launch date" value="2026-04-15" />

Common patterns

1 example

common

Common: min and max constraints

Limit the valid date window when the workflow has a real schedule boundary.

Copy snippet

<DatePicker label="Ship date" min="2026-04-01" max="2026-04-30" />

Edge cases

1 example

edge

Edge: blocked dates

Block specific non-working days or unavailable release slots.

Copy snippet

<DatePicker label="Launch date" disabledDates={['2026-04-19', '2026-04-20']} />

Verification

Curated proof fixtures

Proofs stay visible in the docs so the system shows what it can guarantee, not just what it can render.

default-md

pass

size=md

  • Contrast: 98.5 Lc, 98.5 Lc
  • Target: 48px, 44px
  • Layout: 0 / 280, 320, 360
  • Surface: 320x324

selected-lg

pass

size=lg

  • Contrast: 98.5 Lc, 76.6 Lc
  • Target: 52px, 44px
  • Layout: 0 / 280, 320, 360
  • Surface: 320x324

disabled-sm

pass

size=sm

  • Contrast: 98.5 Lc, 98.5 Lc
  • Target: 44px, 44px
  • Layout: 0 / 280, 320, 360
  • Surface: 320x324