Primitives Date and time
Date field
The native date and time inputs: date, time, datetime-local, month and week. The browser provides segmented entry, the ISO value, validation, locale formatting and its own picker; the package adds a stylesheet and a contract. Tier 0: the field for a table cell or a form without JavaScript; the Date picker is the application date field.
- Tier
- 0 · Native
- Behavior JS
- 0 B brotli · 0 B gzip ·
fixtures/· methodresults.json (native-only) - Platform features
<input type="date">,time,datetime-local,min,max,step,:user-invalid- Shared listeners
- none
- Per-instance listeners
- none
- Lazy state
- none
- Native base
<input type="date|time|datetime-local|month|week">
On this page
Note For an application date field, with the date in a display format, a placeholder, a clear button, a calendar popup and ranges, use the Date picker. It keeps a native date input underneath, so its form value is the one this page describes.
Example
<label for="start">Start date</label>
<input id="start" type="date" name="start" min="2026-01-01" data-slean="date-field" />
<label for="at">Time</label>
<input id="at" type="time" name="at" step="900" data-slean="date-field" />
<label for="when">Date and time</label>
<input id="when" type="datetime-local" name="when" data-slean="date-field" /><script lang="ts">
// Nothing to import: the browser owns the field. The stylesheet is optional.
import '@svelte-lean/styles/date-field.css';
let start = $state('2026-09-28');
</script>
<label for="start">Start date</label>
<input id="start" type="date" name="start" min="2026-01-01" bind:value={start}
data-slean="date-field" />Why this implementation exists
Date entry is where component libraries spend the most JavaScript: masks, parsers, segment focus, locale tables. The platform already does all of it in <input type="date">, with the value in ISO form whatever the locale shows, and min, max and step checked by the form.
Svelte Lean ships the field as it is, sized and colored from the tokens. Its interface is the browser’s: a dd/mm/yyyy mask with no placeholder and a picker glyph and popup that differ in every engine. Under ADR 0007 that is below the bar of an application field, so the Date picker draws one over the same native input; the date field stays for the places where the native control is the point.
The browser owns
- segmented entry in the reader’s locale and the ISO value
- min, max and step validation, :user-invalid after an edit
- the platform picker and its keyboard
- form participation and the label association
Svelte Lean owns
- date-field.css: size, border, colors and the themed picker indicator
- the contract
- documentation; for an application date field with a formatted value, a clear button, a calendar popup and ranges, the Date picker
Usage
The markup needs no package. Install @svelte-lean/styles for the stylesheet; @svelte-lean/primitives adds the typed contract and nothing at runtime.
npm install @svelte-lean/stylespnpm add @svelte-lean/stylesyarn add @svelte-lean/stylesbun add @svelte-lean/stylesimport '@svelte-lean/styles/date-field.css';Use type="date" for a day, time with step in seconds for a time, datetime-local for both. month and week exist but are not in every browser (see below).
Bind the value with bind:value; it is a string in ISO form, or empty.
For a date field in an application interface (a display format, a placeholder, a clear button, a calendar popup, ranges and presets), use the Date picker.
Anatomy
| Part | Element | data-slean-part | Required | Notes |
|---|---|---|---|---|
| root | <input type="date|time|datetime-local|month|week" data-slean="date-field"> | – | yes | A label through <label for> or aria-label; min, max and step for the constraints. |
Runtime profile
Tier 0: the field has no behavior module, the Vite plugin maps date-field to no module, and the native-only fixture proves the path ships no Svelte Lean JavaScript.
Accessibility contract
- A label through
<label for>; a hint or an error througharia-describedby. - Each segment is focusable and announced by the browser; the platform picker is keyboard-operable.
:user-invalidmarks a field only after the user edited it, so an untouched required field is not red.
Keyboard
| Key | When | Result |
|---|---|---|
| digits | focus on a segment | Types the segment and moves on (native) |
| ArrowUp/ArrowDown | focus on a segment | Steps the segment (native) |
| ArrowLeft/ArrowRight | focus in the field | Moves between segments (native) |
Platform features
| Feature | Baseline | Outside the target |
|---|---|---|
date, time, datetime-local | Baseline 2021 | A text input |
month, week | Not Baseline: missing in Firefox and Safari desktop | A text input; validate on the server |
:user-invalid | Baseline 2023 | No invalid border after an edit |
Without JavaScript
Fully functional.
Server rendering
The value attribute in ISO form renders the initial value.
Before hydration
Nothing is attached; the field works before and after hydration alike.
Styling
date-field.css sizes the box to the control height, sets the border, background and text from the tokens, themes the picker indicator through color-scheme, and marks :user-invalid with the danger token. The tokens it reads:
| Token | Default (light) | Applies to |
|---|---|---|
--slean-control-height-md | 2.25rem | min-block-size |
--slean-space-3 | 0.75rem | padding-inline |
--slean-control-border | var(--slean-border-strong) | border |
--slean-radius-md | 0.625rem | border-radius |
--slean-control-bg | var(--slean-surface) | background |
--slean-fg | var(--slean-neutral-12) | color |
--slean-color-scheme | light | color-scheme |
--slean-text-sm | 0.875rem | font-size |
--slean-duration-fast | 100ms | transition |
--slean-ease | cubic-bezier(0.2, 0, 0, 1) | transition |
--slean-space-2 | 0.5rem | margin-inline-start |
--slean-control-border-hover | var(--slean-accent) | border-color |
--slean-control-border-focus | var(--slean-accent) | border-color |
--slean-control-ring | 0 0 0 3px color-mix(in oklch, var(--slean-accent) 22%, transparent) | box-shadow |
--slean-warning | oklch(76% 0.16 80) | border-color |
--slean-control-ring-warning | 0 0 0 3px color-mix(in oklch, var(--slean-warning) 28%, transparent) | box-shadow |
--slean-danger | oklch(55% 0.2 25) | border-color |
--slean-control-ring-danger | 0 0 0 3px color-mix(in oklch, var(--slean-danger) 22%, transparent) | box-shadow |
--slean-control-border-disabled | var(--slean-border) | border-color |
--slean-control-bg-disabled | var(--slean-muted) | background-color |
--slean-fg-muted | var(--slean-neutral-11) | color |
--slean-text-md | 1rem | font-size |
State selectors the stylesheet targets, all from the platform or ARIA: ::-webkit-calendar-picker-indicator, ::-webkit-datetime-edit-fields-wrapper, :disabled, :focus-visible, :hover, :user-invalid, [aria-invalid="true"].
Variant attributes: data-status (warning, error).
Compatibility notes
date, time and datetime-local are Baseline 2021. month and week fall back to a text input in Firefox and Safari desktop: validate the value on the server.
Testing
apps/playground/tests/primitives/calendar.spec.tsPlaywright: the grid, the date picker and the range picker in Chromiumpackages/styles/testsstatic checks of the stylesheet (layers, tokens, specificity, dark parity)fixtures/native-onlyconsumer build asserting that no behavior runtime ships (invariant A)
Source
packages/primitives/src/date-field/contract.mdthe contract in prose: semantics, keyboard, focus, ARIA, SSR, JS-disabled behaviorpackages/primitives/src/date-field/contract.tstyped constants: name, tier, base, parts, options, eventspackages/styles/css/date-field.cssthe optional stylesheet