Components / forms

DatePicker

DateField gained an adornment prop for this. It passes straight through to Field; the date field itself puts nothing there, because its message row already reports what was parsed.

Rendered from the package · open on its own

Summary

A date typed, or picked from a month — the text field always, the calendar when it helps.

APG patternGrid, in a dialog
Built onnative elements
Statusstable
Since0.2.0

Anatomy

Root: data-se="date-picker". Explicit roles: dialog.

PartElementRequired
floater<div>no
toggle<datefield>yes

Properties

Open — see DatePicker.d.ts.

States

StateExpressed as
Disabled:disabled
Focused:focus-visible
Hover:hover
Open or closeddata-state

Behavior

Neither half owns the value. DateField parses and Calendar selects; both report the same YYYY-MM-DD and this holds nothing they do not. Choosing from the calendar calls onChange with the same shape typing does, so a caller cannot tell which path produced a date — and should not have to.

The calendar opens on the value's month, or this month when there is none. Never on a month the reader has to navigate away from.

Escape closes it and focus returns to the toggle. A popup that leaves focus where the document happens to put it drops a keyboard reader at the top of the page. A click outside closes it without moving focus, because the pointer has already gone somewhere.

Accessibility

The popup is a dialog, not a listbox. aria-haspopup="dialog" is what a grid navigated in two dimensions is. listbox would promise arrow keys that move through one sequence, and there is no such sequence in a month.

The text input is the path that always works. A calendar is a two-dimensional keyboard model; typing eight digits is one. Anyone on a switch, or reading with a screen reader, gets a complete route to any date without opening the calendar at all — which is why the field is the component and the calendar is an affordance on it.

The toggle is named, not labelled by its glyph. openLabel becomes its accessible name; its visible content is an icon and announces nothing.

Keyboard

KeyWhat it does
AnythingTypes into the field — the calendar is never required
EscapeCloses the calendar and returns focus to the toggle

Inside the calendar, Calendar's own grid keys apply.

Roles, states and properties

AttributeSet by
aria-controlsset at render
aria-expandedset at render
aria-haspopupalways dialog
aria-hiddenalways true
aria-labelset at render
rolealways dialog

Focus

The field and the toggle are each a tab stop. The open calendar adds one more — its grid — and closing returns focus to the toggle.

Screen reader

Not recorded as verified. Stage 4 of the readiness ladder — driving each component with VoiceOver and NVDA — is unstarted across the package, and no component should claim otherwise until docs/journal/ records the session that did it.

Contrast and target size

npm run check:contrast audits every color pair this component uses across all four skins, light and dark, and fails the build on a shortfall. Two waivers are on the record in docs/audit/DEFERRED.md.

It sets no target size of its own; anything interactive inside it brings its own.

Tested

_Nothing asserts against this component._

Known gaps

_No upstream requirement is recorded as not applicable._

Appearance

TokenUsed for
--se-borderborder
--se-border-widthborder
--se-duration-fastanimation
--se-ease-decelerateanimation
--se-focus-coloroutline
--se-focus-offsetoutline-offset
--se-focus-widthoutline
--se-icon-mdblock-size, inline-size
--se-icon-smblock-size, inline-size
--se-layer-floatingz-index
--se-radius-lgborder-radius
--se-radius-smborder-radius
--se-shadow-floatingbox-shadow
--se-space-1inset-block-start
--se-space-2inset-block-start
--se-surfacebackground
--se-textcolor

Motion

The calendar fades in on the shared float animation. It does not slide: a panel that arrives from a direction implies it came from somewhere, and this one is anchored to the field it belongs to.

Content

The toggle says what it opens, not what it is: Choose a date from a calendar, not Calendar.

The field's own copy is unchanged — the format hint before a date, the parsed date after. Opening the calendar does not replace that.

Usage

Use DateField alone when the date is known — a birthday, an invoice date. A calendar for a date someone can recite is twelve clicks instead of eight keystrokes.

Use this when the date is being chosen — next Tuesday, the first free Friday, a delivery slot. Both paths stay available either way.

When not to use it. For a range. That is DateRangePicker, where the second date constrains the first and hovering previews the span; two of these side by side cannot express either.

Notes

The adornment slot is inert by default — most adornments report state rather than offer an action, so Field sets pointer-events: none on it. The toggle takes its events back explicitly, which is the one place that rule is waived and the reason it is waived narrowly.

DateField gained an adornment prop for this. It passes straight through to Field; the date field itself puts nothing there, because its message row already reports what was parsed.