DateField
Overview
A segmented date input that keeps day, month, year, and optional time values as separate keyboard-editable parts while still submitting a native form value. Use it for compact date entry where typing should be fast — birth dates, expiry dates, or any single date that needs validation against a range. For a date chosen from a calendar popup, prefer SDatePicker; for browsing a calendar grid, use SCalendar.
Usage
Features
- 🧩 Segmented input — each date part (day/month/year, optional hour/minute/second/dayPeriod) is an independent editable segment
- ⌨️ Full keyboard editing — arrow keys increment/decrement, typing fills digits, auto-advance to the next segment, Backspace deletes,
Enter/focus-out commits - 🎚 Controlled / uncontrolled —
v-modelanddefaultValuebacked byuseControllableState, plusupdate:placeholder - ⛓ Range validation —
minValue/maxValue/isDateUnavailabledrive thedata-invalid+aria-invalidstate - 🕐 Granularity & time —
granularity(day/hour/minute/second), 12/24-hourhourCycle, anddayPeriodsegments - 📝 Form native — a visually hidden input (
name/required/min/max) submits the ISO value with the owning form - 🚫 Disabled / readonly — both render proper
data-*/aria-*state and block editing - 🧩 Extensible —
leading/trailingslots plusui.root/ui.inputclass overrides, built on AriaDateFieldRoot/DateFieldInput
Component family
SDateField— the styled wrapper that forwards props to the Aria compact and injectsdateFieldVariantsclassesDateFieldCompact(Aria) — data-driven composition ofDateFieldRoot+ per-segmentDateFieldInput; import from@vean/aria/date-fieldfor unstyled usageDateFieldRoot/DateFieldInput(Aria) — the state owner (segments, validation, hidden input) and a single editable segment
Demos
Basic
Value: Sun Apr 19 2026 00:00:00 GMT+0000 (Coordinated Universal Time)
With Time
Value: [object Object]
Custom Styling
API
Aria Layer
4DateField
Props
| Prop | Type | Default | Description |
|---|---|---|---|
class | ClassValue | — | Additional class names applied to the root element. |
size | ThemeSize | — | Visual size of the component. |
ui | Partial<DateFieldUi> | — | Per-slot class overrides for the component. |
inputProps | DateFieldInputProps | — | Properties forwarded to the input element. |
id | string | — | Id. |
granularity | Granularity | — | Granularity. |
hourCycle | HourCycle | — | Hour cycle. |
step | DateStep | — | Step. |
hideTimeZone | boolean | — | Whether hide time zone. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
modelValue | DateValue | — | Current model value. |
defaultValue | DateValue | — | Default value. |
disabled | boolean | — | Whether the component is disabled. |
dir | Direction | — | Reading direction of the component. |
placeholder | DateValue | — | Placeholder. |
readonly | boolean | — | Whether the component is readonly. |
locale | string | — | Locale. |
defaultPlaceholder | DateValue | — | Default placeholder. |
maxValue | DateValue | — | Max value. |
minValue | DateValue | — | Min value. |
isDateUnavailable | DateMatcher | — | Whether the date is unavailable. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | DateValue | undefined | Emitted when the model value changes. |
update:placeholder | DateValue | Emitted when the placeholder value changes. |
DateFieldCompact
Props
| Prop | Type | Default | Description |
|---|---|---|---|
inputProps | DateFieldInputProps | — | Properties forwarded to the input element. |
id | string | — | Id. |
granularity | Granularity | — | Granularity. |
hourCycle | HourCycle | — | Hour cycle. |
step | DateStep | — | Step. |
hideTimeZone | boolean | — | Whether hide time zone. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
modelValue | DateValue | — | Current model value. |
defaultValue | DateValue | — | Default value. |
disabled | boolean | — | Whether the component is disabled. |
dir | Direction | — | Reading direction of the component. |
placeholder | DateValue | — | Placeholder. |
readonly | boolean | — | Whether the component is readonly. |
locale | string | — | Locale. |
defaultPlaceholder | DateValue | — | Default placeholder. |
maxValue | DateValue | — | Max value. |
minValue | DateValue | — | Min value. |
isDateUnavailable | DateMatcher | — | Whether the date is unavailable. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | DateValue | undefined | Emitted when the model value changes. |
update:placeholder | DateValue | Emitted when the placeholder value changes. |
DateFieldInput
Props
| Prop | Type | Default | Description |
|---|---|---|---|
part | SegmentPart | — | Part. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
DateFieldRoot
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | Id. |
granularity | Granularity | — | Granularity. |
hourCycle | HourCycle | — | Hour cycle. |
step | DateStep | — | Step. |
hideTimeZone | boolean | — | Whether hide time zone. |
name | string | — | The name of the field. Submitted with its owning form as part of a name/value pair. |
required | boolean | — | When `true`, indicates that the user must set the value before the owning form can be submitted. |
modelValue | DateValue | — | Current model value. |
defaultValue | DateValue | — | Default value. |
disabled | boolean | — | Whether the component is disabled. |
dir | Direction | — | Reading direction of the component. |
placeholder | DateValue | — | Placeholder. |
readonly | boolean | — | Whether the component is readonly. |
locale | string | — | Locale. |
defaultPlaceholder | DateValue | — | Default placeholder. |
maxValue | DateValue | — | Max value. |
minValue | DateValue | — | Min value. |
isDateUnavailable | DateMatcher | — | Whether the date is unavailable. |
asChild | boolean | — | Change the default rendered element for the one passed as a child, merging their props and behavior. |
as | AsTag | Component | 'div' | The element or component this component should render as. Can be overwrite by `asChild` |
Emits
| Emit Name | Parameters | Description |
|---|---|---|
update:modelValue | DateValue | undefined | Emitted when the model value changes. |
update:placeholder | DateValue | Emitted when the placeholder value changes. |
Slots
| Slot Name | Parameters | Description |
|---|---|---|
default | DateFieldRootSlotProps | — |
Notes
Architecture and benchmark differences
DateFieldRoot owns the value (via useControllableState), derives the segment layout with Intl.DateTimeFormat formatters, and runs validation through isInvalid. Each DateFieldInput binds the useDateField composable, which implements per-part keydown logic (increment/decrement/typing/auto-advance/delete) shared by the time-field family. Editing mutates a segmentValues shallowRef; the root commits the assembled DateValue once every segment is filled. The segmented date-field pattern originates from reka-ui (Radix); the benchmark libraries express date input as a plain text input plus a picker popup instead.
| Capability | VeanUI | Ant Design | Element Plus | Mantine | Naive UI | shadcn |
|---|---|---|---|---|---|---|
| Aria/styled split | ✅ | — | — | — | — | — |
| Segmented editable parts | ✅ | — | — | — | — | — |
| Controlled / uncontrolled | ✅ | ✅ | ✅ | ✅ | ✅ | — |
| Keyboard increment/typing | ✅ | — | — | — | — | — |
| Auto-advance between parts | ✅ | — | — | — | — | — |
| Range validation | ✅ | ✅ | ✅ | ✅ | ✅ | — |
isDateUnavailable | ✅ | — | — | — | — | — |
| Granularity (minute/second) | ✅ | — | — | — | — | — |
12/24-hour dayPeriod | ✅ | — | — | — | — | — |
| Disabled / readonly | ✅ | ✅ | ✅ | ✅ | ✅ | — |
| Native form submission | ✅ | ✅ | ✅ | ✅ | ✅ | — |
leading/trailing slots | ✅ | — | — | — | — | — |
Cautions
- A segment is committed as soon as every part is filled; deleting the last digit emits
update:modelValuewithundefined. defaultValueis only read on mount — usev-modelfor external control.- The root uses
role="group"and each editable partrole="spinbutton"witharia-valuemin/aria-valuemax/aria-valuenow; addaria-labelto the field so screen readers announce the whole control. - Form submission requires
name;required/min/maxare reflected on the hidden input but do not run custom validation. granularity="day"renderstype="date"; time granularities rendertype="datetime-local"on the hidden input.readonlydiffers fromdisabled: the field stays focusable and visible but blocks editing.
FAQ
How do I clear the value?
Backspace on a single-digit segment (or Backspace twice on a two-digit segment) empties it and emits update:modelValue with undefined — handle the undefined in the parent. The segments then fall back to placeholder styling.
How do I restrict the selectable range?
Pass minValue/maxValue — the field marks itself data-invalid (plus aria-invalid on segments) when the value falls outside. isDateUnavailable accepts a predicate for arbitrary exclusions.
How do I use 12-hour time?
Pass hourCycle={12} (or let it follow the locale) — the hour segment becomes 1–12 and a dayPeriod (AM/PM) segment appears. Arrow keys and a/p keys toggle the period.
What is the difference between SDateField and SDatePicker?
SDateField is a pure segmented input with no popup — best for fast typing and form submission. SDatePicker embeds a DateField alongside a calendar popover for visual selection.
How do I customize the look?
Use ui.root/ui.input for class overrides, or leading/trailing slots to place icons/units around the segments. For fully unstyled control, compose DateFieldRoot/DateFieldInput from @vean/aria/date-field.