Date picker
A themed date editor and calendar, alone or as a from/to pair, backed by native form values and constraints.
stable · light DOM · 4.0.0. Theme-owned date/time editor and controls backed by the original native input for form values and constraints. Native input is the no-JavaScript fallback.
Live variants
default
Within 2026.
<j3w1-date-picker id="example-date-picker-default"><div class="date-picker">
<label class="date-picker-label" for="example-date-picker-default-dp-release">Release date</label>
<div class="date-picker-root">
<input class="date-picker-input" id="example-date-picker-default-dp-release" type="date" value="2026-09-06" min="2026-01-01" max="2026-12-31" aria-describedby="example-date-picker-default-dp-release-help example-date-picker-default-dp-release-message" name="example-date-picker-default-dp-release">
</div>
<p class="date-picker-help" id="example-date-picker-default-dp-release-help">Within 2026.</p>
<p class="date-picker-message" id="example-date-picker-default-dp-release-message">✕ Choose a date in 2026.</p>
</div></j3w1-date-picker>range
<j3w1-date-picker id="example-date-picker-range"><fieldset class="date-picker date-picker-range">
<legend class="date-picker-legend">Report period</legend>
<div class="date-picker-pair">
<div class="date-picker-half">
<label class="date-picker-label" for="example-date-picker-range-dp-from">From</label>
<div class="date-picker-root">
<input class="date-picker-input" id="example-date-picker-range-dp-from" type="date" value="2026-09-01" aria-describedby="example-date-picker-range-dp-range-help example-date-picker-range-dp-range-message" name="example-date-picker-range-dp-from">
</div>
</div>
<span class="date-picker-separator" aria-hidden="true">–</span>
<div class="date-picker-half">
<label class="date-picker-label" for="example-date-picker-range-dp-to">To</label>
<div class="date-picker-root">
<input class="date-picker-input" id="example-date-picker-range-dp-to" type="date" value="2026-09-30" aria-describedby="example-date-picker-range-dp-range-help example-date-picker-range-dp-range-message" name="example-date-picker-range-dp-to">
</div>
</div>
</div>
<p class="date-picker-help" id="example-date-picker-range-dp-range-help">Inclusive; at most 92 days.</p>
<p class="date-picker-message" id="example-date-picker-range-dp-range-message">✕ The end date is before the start date.</p>
</fieldset></j3w1-date-picker>Install and register
Use the exact version. If npm publication is pending, install the release tarball from the installation guide.
npm install --save-exact @j3w1/ui@4.0.0import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/date-picker.css';
import '@j3w1/ui/register/date-picker';Insert the maintained markup above after loading these imports. Its native children provide accessible names and form behavior; the empty custom tag alone does not create a control.
Copy the complete implementation
npx --package=@j3w1/ui@4.0.0 j3w1-ui copy date-picker --out ./vendor/j3w1/date-pickerThe CLI verifies every file before writing and refuses overwrites. Serve the output over HTTP and open index.html. Keep its modules, CSS, tokens and licence notices together.
Public API
attributes
| Name | Type / signature | Meaning |
|---|---|---|
disabled | CustomEvent | Disable the native controls owned by this instance. |
loading | CustomEvent | Mark the primary control busy and prevent duplicate activation. |
value | CustomEvent | Forwards value to the primary native control. |
required | CustomEvent | Forwards required to the primary native control. |
readonly | CustomEvent | Forwards readonly to the primary native control. |
checked | CustomEvent | Forwards checked to the primary native control. |
properties
| Name | Type / signature | Meaning |
|---|---|---|
disabled | boolean | Delegates disabled state to native children. |
name | string | Native control name; application form keys remain explicit. |
value | string | Primary native value; assignment does not fabricate user events. |
checked | boolean | Native checkbox state. |
required | boolean | Native required constraint. |
readOnly | boolean | Native readonly property. |
form | HTMLFormElement | null | Owning native form. Read only. |
methods
| Name | Type / signature | Meaning |
|---|---|---|
refresh | (): void | Reconnect behavior after replacing native child structure. |
focus | (options?: FocusOptions): void | Focus the first usable native control. |
checkValidity | (): boolean | Check owned native constraints. |
reportValidity | (): boolean | Report the first invalid owned control. |
clear | (): void | Clear an editable primary input and emit native input/change. |
events
| Name | Type / signature | Meaning |
|---|---|---|
j3w1-change | CustomEvent | Native change from an owned control, alongside the original native event. |
Dependencies and verification
Registered components: none. Style dependencies: none.
Package presence establishes an available implementation. Actual passes depend on the tested artifact and environment. Read specification execution evidence; read packed-consumer evidence; inspect the complete state matrix.
Full implementation manifest, API and token dependency closure
Canonical specification
Date picker date-picker
A themed date editor and calendar, alone or as a from/to pair, backed by native form values and constraints.
Report an issue with this component
Tokens
Focus a role to inspect its values; follow its link for persistent usage and source details.
| Part | Role | Value | Use |
|---|---|---|---|
root.bg | color.surface.inputapproveduse | #000000 | Form-control fill. |
root.border | color.border.controlapproveduse | #c81a1a | D-041 owner correction: red control and floating-frame borders, distinct from rose text. |
root.bg-hover | color.interaction.hover.bgapproveduse | #1c1010 | D-041 interaction.hover.bg: color.primitive.modern.hover. |
root.border-focus | color.border.activeobserveduse | #e53935 | Active or focused control border. |
root.ring | color.interaction.focus.ringobserveduse | #e53935 | 1px dashed focus ring on controls and rows. |
root.ring-invalid | color.interaction.focus.ring-containerobserveduse | #ffa2a7 | Focus colour for containers and explicitly mapped filled controls (D-015); component rules determine ring geometry. |
root.border-invalid | color.status.danger.borderobserveduse | #e53935 | Danger border, 2px on invalid inputs. |
root.border-disabled | color.border.disabledapproveduse | #482b2b | D-041 border.disabled: color.primitive.modern.divider. |
root.bg-disabled | color.interaction.disabled.bgapproveduse | #0d0707 | D-041 interaction.disabled.bg: color.primitive.modern.panel. |
root.border-readonly | color.border.dividerapproveduse | #482b2b | D-041 border.divider: color.primitive.modern.divider. |
root.bg-readonly | color.surface.canvasapproveduse | #000000 | Page and terminal background. |
input.text | color.text.defaultapproveduse | #e99499 | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
input.text-disabled | color.text.disabledapproveduse | #a3676b | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
input.caret | color.code.caretapproveduse | #ffa2a7 | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
label.text | color.text.brightapproveduse | #ffa2a7 | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
legend.text | color.text.brightapproveduse | #ffa2a7 | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
separator.text | color.text.mutedapproveduse | #d4868b | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
help.text | color.text.mutedapproveduse | #d4868b | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
message.text | color.status.danger.textobserveduse | #f07178 | D-041 readable error text on neutral surfaces and native warning tints. |
calendar.bg | color.surface.raisedapproveduse | #140b0b | D-041 surface.raised: color.primitive.modern.raised. |
calendar.border | color.border.overlayapproveduse | #c81a1a | D-041 owner correction: red control and floating-frame borders, distinct from rose text. |
calendar.text | color.text.defaultapproveduse | #e99499 | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
calendar.selected-bg | color.interaction.selection.bgapproveduse | #531310 | Selected row, tab, workspace; D-027 recessed the fill, leaving the 2px indicator and the check to carry selection. |
calendar.selected-text | color.interaction.selection.textobserveduse | #f4eeee | Text on the selection. |
State matrix
Every declared state and combination, statically rendered; the default cell is live. Sizes: compact, comfortable (switch with the density control above).
| State | Single date | From / to |
|---|---|---|
default | Within 2026. | |
hover | ||
focus-visible | ||
invalid | ||
invalid+focus-visible | ||
disabled | ||
read-only |
Purpose
Choose a date by typing or from a themed calendar; a range is two separately labelled date controls. D-025: theme-owned web controls, not browser popup styling.
Anatomy
A label, editor, calendar trigger, format hint and validation message. The native date input stays the successful form control, owns value, defaults and constraints, and is hidden only after enhancement.
States
| State | Visual | Non-colour channel |
|---|---|---|
| default | color.text.default on color.surface.input, 1px color.border.control | — |
| hover | background → color.interaction.hover.bg | hover-capable pointers only |
| focus-visible | border → color.border.active; the canonical focus ring | the ring |
| invalid | 2px color.status.danger.border; a linked message | border 1 → 2px; ✕ glyph; aria-invalid |
| invalid+focus-visible | the danger border and the ring in color.interaction.focus.ring-container at −4px | double boundary |
| disabled | color.text.disabled on color.interaction.disabled.bg, border color.border.disabled; editor and calendar actions unavailable | disabled; cursor: not-allowed |
| read-only | readable text on color.surface.canvas, no box, 1px dotted color.border.divider bottom edge; the calendar cannot open | readonly; dotted edge |
Keyboard
Arrows move by a day or a week. Tab leaves normally; the calendar is a nonmodal popup.
Accessibility
The visible editor receives the original label, descriptions, required and error state. Format hints are always available. Native min, max, step and required stay authoritative. Invalid entry focuses the visible editor and shows a theme-owned message. Calendar selection is a fill, focus a separate ring. Disabled dates cannot be chosen. A range rejects an end before its start. Form reset restores the native defaults. Automated evidence records its browser, states and limits and is not a manual screen-reader acceptance.
Portability
The package and the complete copy distribution include the renderer; the public control enhancement applies it to existing native markup. Without JavaScript, and on non-web platforms, the control stays native.
Non-examples
An unthemed host popup presented as themed. A second named input duplicating form values. Dropping native constraints, labels or reset. Literal colours, rounded corners, or a selected fill with no distinct focus boundary.
Contrast report
20 declared pairs measured on resolved sRGB values with the WCAG 2.x formula; 0 waived (decorative only), 0 failing. A pass is a design target for the named role, not an application-wide conformance claim.
| Pair | State | Kind | Foreground | Background | Ratio | Min | Result |
|---|---|---|---|---|---|---|---|
| date-picker default text | default | text | color.text.default #e99499 | color.surface.input #000000 | 9.16 | 4.5 | pass |
| date-picker default border | default | ui | color.border.control #c81a1a | color.surface.input #000000 | 3.62 | 3 | pass |
| date-picker hover text | hover | text | color.text.default #e99499 | color.interaction.hover.bg #1c1010 | 8.10 | 4.5 | pass |
| date-picker hover border | hover | ui | color.border.control #c81a1a | color.interaction.hover.bg #1c1010 | 3.20 | 3 | pass |
| date-picker focus-visible text | focus-visible | text | color.text.default #e99499 | color.surface.input #000000 | 9.16 | 4.5 | pass |
| date-picker focus-visible border | focus-visible | ui | color.border.active #e53935 | color.surface.input #000000 | 4.97 | 3 | pass |
| date-picker focus-visible outline | focus-visible | ui | color.interaction.focus.ring #e53935 | color.surface.input #000000 | 4.97 | 3 | pass |
| date-picker invalid text | invalid | text | color.text.default #e99499 | color.surface.input #000000 | 9.16 | 4.5 | pass |
| date-picker invalid border | invalid | ui | color.status.danger.border #e53935 | color.surface.input #000000 | 4.97 | 3 | pass |
| date-picker invalid+focus-visible text | invalid+focus-visible | text | color.text.default #e99499 | color.surface.input #000000 | 9.16 | 4.5 | pass |
| date-picker invalid+focus-visible border | invalid+focus-visible | ui | color.status.danger.border #e53935 | color.surface.input #000000 | 4.97 | 3 | pass |
| date-picker invalid+focus-visible outline | invalid+focus-visible | ui | color.interaction.focus.ring-container #ffa2a7 | color.surface.input #000000 | 10.98 | 3 | pass |
| date-picker read-only text | read-only | text | color.text.default #e99499 | color.surface.canvas #000000 | 9.16 | 4.5 | pass |
| validation message on the canvas | — | text | color.status.danger.text #f07178 | color.surface.canvas #000000 | 7.34 | 4.5 | pass |
| help text and the range separator on the canvas | — | text | color.text.muted #d4868b | color.surface.canvas #000000 | 7.58 | 4.5 | pass |
| disabled text (exempt; house floor 3:1) | disabled | ui | color.text.disabled #a3676b | color.interaction.disabled.bg #0d0707 | 4.48 | 3 | pass |
| disabled border (exempt) | disabled | ui | color.border.disabled #482b2b | color.interaction.disabled.bg #0d0707 | 1.58 | 1 | pass |
| read-only bottom edge (decorative; the field has no box) | read-only | ui | color.border.divider #482b2b | color.surface.canvas #000000 | 1.66 | 1 | pass |
| calendar text | — | text | color.text.default #e99499 | color.surface.raised #140b0b | 8.46 | 4.5 | pass |
| selected date | — | text | color.interaction.selection.text #f4eeee | color.interaction.selection.bg #531310 | 12.47 | 4.5 | pass |
Keys
| Key | Action |
|---|---|
| Tab / Shift+Tab | Moves through the editor, calendar trigger and other controls. |
| Alt+Down | Opens the calendar from the editor. |
| Arrows / Home / End | Moves among dates; Home and End reach the beginning and end of the week. |
| PageUp / PageDown | Moves to the previous or next month. |
| Enter / Space | Chooses a focused calendar date or activates a month button. |
| Escape | Closes the calendar and returns focus to the editor. |
For agents
Component JSON ·Implementation brief ·Build a task kit ·
Related: text-field time-picker field fieldset
Stress fixtures: FX-LONG FX-320 FX-ZOOM-200 FX-I18N FX-RTL FX-RM FX-HC FX-STATE-MATRIX