Skip to content

Date Input

Form Inputs / Date and TimeSince 0.1.0
import { DateInput } from '@absoluteui/components/date-input';
import '@absoluteui/components/date-input/style.css';

Using Angular? See Date Input for Angular.

Keyboard-first date or date-time entry using numeric segments ordered for the locale. Values are explicit types:

  • date granularity produces a PlainDate;
  • minute granularity produces an Instant, resolved in the configured timezone with a documented DST policy.
  • Entering known dates such as birth dates or due dates.
  • Entering an exact moment (meeting time) in a specific timezone.
  • Browsing dates visually: use Date Picker or DateTime Picker. Choosing ranges: use Date Range Picker.
  • Relative or fuzzy dates (‘next week’).
import { plainDate, plainDateToString, type PlainDate } from '@absoluteui/core';
import { DateInput, type DateInputChangeDetail } from '@absoluteui/components/date-input';
const host = document.createElement('div');
document.body.append(host);
DateInput.create(host, { label: 'Due date', name: 'due', min: plainDate(2026, 1, 1), required: true });
host.addEventListener('aui-change', (event) => {
const { value } = (event as CustomEvent<DateInputChangeDetail>).detail;
if (value?.kind === 'PlainDate') {
const due: PlainDate = value;
document.title = plainDateToString(due);
}
});

Exact meeting time in a configured timezone

Section titled “Exact meeting time in a configured timezone”
import { configureAbsoluteUI, instantToString } from '@absoluteui/core';
import { DateInput, type DateInputChangeDetail } from '@absoluteui/components/date-input';
configureAbsoluteUI({ common: { timezone: 'Asia/Kolkata' }, components: { dateInput: { disambiguation: 'reject' } } });
const host = document.createElement('div');
document.body.append(host);
DateInput.create(host, { label: 'Meeting time', granularity: 'minute' });
host.addEventListener('aui-change', (event) => {
const { value } = (event as CustomEvent<DateInputChangeDetail>).detail;
if (value?.kind === 'Instant') document.title = instantToString(value);
});
import { configureAbsoluteUI } from '@absoluteui/core';
import { DateInput } from '@absoluteui/components/date-input';
import '@absoluteui/components/date-input/style.css';
configureAbsoluteUI({ timezone: 'America/New_York' });
const host = document.querySelector<HTMLElement>('#meeting');
if (host) DateInput.create(host, { label: 'Meeting time', granularity: 'minute', name: 'meeting' });
import { plainDate } from '@absoluteui/core';
import { DateInput } from '@absoluteui/components/date-input';
const host = document.createElement('div');
document.body.append(host);
DateInput.create(host, { label: 'Due date', name: 'due', min: plainDate(2026, 1, 1) });
<div class="aui-date-input"> (consumer host)
<div class="aui-date-input__label" id>
<div class="aui-date-input__group" role="group" aria-labelledby aria-describedby>
<div class="aui-date-input__fields">
<input class="aui-date-input__segment aui-date-input__segment--month" aria-label="Month">
<span class="aui-date-input__separator" aria-hidden="true">/</span> ...
</div>
</div>
<div class="aui-date-input__description"> <div class="aui-date-input__hint"> <div class="aui-date-input__error">
<input type="hidden" name>
</div>
DateInput.create(host: HTMLElement, options: DateInputOptions): DateInput

Global configuration key: dateInput (see Configuration).

Option Type Default Description
label string Group label and accessible name. Required.
value PlainDate | Instant | null null PlainDate for date granularity; Instant for minute granularity.
min PlainDate | Instant | null Inclusive lower bound.
max PlainDate | Instant | null Inclusive upper bound.
name string Form field name for the ISO 8601 hidden input.
description string Help text referenced by aria-describedby.
required boolean false Empty value is invalid (value-missing).
disabled boolean false Disables all segments.
readOnly boolean false Prevents editing.
trailing HTMLElement Advanced: element appended inside the group boundary after the segments (used by Date Picker for its calendar button). Focus moving into it does not mark the field touched.
formControl boolean true Advanced, read at creation: false skips registration with Form, for composite controls such as Date Picker that register themselves. Set at creation only.
granularity 'date' | 'minute' "date" Value type and segments. Globally configurable. Set at creation only.
hourCycle 'auto' | 'h12' | 'h23' "auto" 12/24-hour clock; auto follows the locale. Globally configurable.
locale string "en-US" Segment order, labels, messages, formatting. Globally configurable. Inherited from common configuration.
timezone string (IANA) "UTC" Zone for minute granularity. Globally configurable. Inherited from common configuration.
disambiguation 'compatible' | 'earlier' | 'later' | 'reject' "compatible" DST policy for nonexistent/ambiguous local times. Globally configurable. Inherited from common configuration.
direction 'ltr' | 'rtl' "ltr" Arrow-key segment navigation direction. Globally configurable. Inherited from common configuration.
Property Type Description
host HTMLElement Consumer-provided host (children are owned by the component).
group HTMLDivElement role=group container of the segments.
value PlainDate | Instant | null Current valid value, or null when empty/invalid.
validity { valid: boolean; error: DateInputError | null; localTimeStatus: 'exact' | 'ambiguous' | 'nonexistent' | null } Validation state.
name string | null Form field name.
label string Label text.
disabled boolean Disabled state.
dirty boolean Value differs from the initial value.
touched boolean Focus has left the control at least once.
localValue PlainDateTime | null Minute granularity: the complete wall-clock date and time in the segments, even when the zone rejects it; else null.
Method Description
setValue(value: PlainDate | Instant | null): void Programmatic value (no aui-change).
setLocalValue(value: PlainDateTime | null): void Minute granularity, for composite controls: write a wall-clock date-time resolved as if typed (timezone, disambiguation, DST hint or error). No aui-change.
update(options: Partial<DateInputOptions>): void Merge and apply options; init-only options throw.
reportValidity(): boolean Show messages immediately; returns validity.
destroy(): void Remove listeners, subscriptions, and rendered children.
setCustomError(message: string | null): void External error (server, cross-field rule); cleared when the user changes the value.
focus(): void Focus the control.
reset(): void Restore the initial value and clear touched/submitted state (no aui-change).
getFormValue(): string | null ISO 8601 value (YYYY-MM-DD or instant with Z), or null when empty or invalid.
Event Detail Bubbles Cancelable Description
aui-change { value: PlainDate | Instant | null; validity: DateInputValidity } Yes No User edit changed the value or validity.

All rules live in the aui.components cascade layer, so application styles override them without specificity battles.

Class Purpose
aui-date-input Host.
aui-date-input--invalid | --disabled State modifiers on the host.
aui-date-input__label Group label.
aui-date-input__group role=group control surface.
aui-date-input__segment Segment input; –year/–month/–day/–hour/–minute/–dayPeriod modifiers.
aui-date-input__separator Locale separator (aria-hidden).
aui-date-input__description | __hint | __error Help, timezone/DST hint, and error text.

Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.

--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-disabled-bg | --aui-color-error-fg | --aui-color-focus-ring | --aui-color-selected | --aui-color-selected-text | --aui-color-surface | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-control-height-md | --aui-control-padding-x | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-weight-medium | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-space-1

type DateInputValue = PlainDate | Instant;
type DateInputError = 'incomplete' | 'invalid-date' | 'value-missing' | 'range-underflow' | 'range-overflow' | 'nonexistent-time' | 'ambiguous-time';
interface DateInputValidity { readonly valid: boolean; readonly error: DateInputError | null; readonly localTimeStatus: 'exact' | 'ambiguous' | 'nonexistent' | null }
interface DateInputChangeDetail { value: DateInputValue | null; validity: DateInputValidity }

Pattern: Labelled group of labelled text inputs (segmented date field). No APG pattern exists for segmented date fields; native text inputs are used for maximum assistive technology compatibility.

Key Context Action
Digits Segment focused Enter value; auto-advance when complete.
ArrowUp / ArrowDown Segment focused Increment/decrement with wrap (year clamps); toggles AM/PM.
ArrowLeft / ArrowRight Caret at segment edge Move to previous/next segment (mirrored in RTL).
Backspace Empty segment Move to previous segment.
/ - . : , Space Numeric segment Pad the current value and advance.
A / P AM/PM segment Set AM or PM.
Tab / Shift+Tab Any Move between segments and out of the group.
Element Role
group container group
each segment textbox (native input, inputmode=numeric)
separators none (aria-hidden=true)
Attribute Element Value
aria-labelledby group id of the visible label
aria-label segment Localized segment name (Year, Month, Day, Hour, Minute, AM/PM)
aria-describedby group description, timezone/DST hint, and error ids as applicable
aria-invalid segment true while an error message is shown

Each segment is a tab stop; focusing selects its content. Focused segment is highlighted with selected colors and a focus outline.

Criterion Level Note
1.3.1 Info and Relationships A
1.3.5 Identify Input Purpose AA
2.1.1 Keyboard A
2.4.7 Focus Visible AA
3.3.1 Error Identification A
3.3.2 Labels or Instructions A
3.3.3 Error Suggestion AA
4.1.2 Name, Role, Value A

Automated test results: Accessibility and compliance.

  • Error messages identify the problem and, for DST cases, the timezone.
  • Adjustments caused by daylight-saving rules are disclosed in the hint rather than applied silently.
  • Each segment is a separate tab stop; some users may prefer a single field. Manual screen-reader and user testing is pending.

empty, incomplete, valid, invalid-date, value-missing, range-underflow, range-overflow, nonexistent-time, ambiguous-time, disabled, read-only.

From Trigger To
empty First digit incomplete (message shown only after blur or reportValidity())
incomplete All segments filled valid, or invalid-date, range-underflow, range-overflow, nonexistent-time, ambiguous-time
any Segment cleared incomplete, or empty (value-missing if required)
  • Error messages name the problem; DST messages also name the timezone.
  • Daylight-saving adjustments are disclosed in the hint, never applied silently.
  • Each segment is a tab stop.
  • Verified with axe (WCAG 2.2 AA) in 3 themes. Manual screen-reader and user testing is pending.

Segments wrap inside the group in narrow containers. The group fits its content, up to 100% of the container width.

Segment order comes from the locale’s Intl pattern. Digits stay LTR and isolated. Arrow-key segment navigation mirrors in RTL.

Token-driven. In forced-colors mode, the focused segment uses Highlight/HighlightText.

configureAbsoluteUI({ common: { timezone: 'Europe/London' }, components: { dateInput: { hourCycle: 'h23' } } });

Instance options override global and theme defaults. granularity is init-only; all other options are dynamic and rebuild the segments while preserving the entered values.

  • Date granularity: timezone-independent PlainDate. The calendar date never shifts.
  • Minute granularity: wall-clock input is resolved in timezone. The default is UTC; the host timezone is never used.

DST handling in minute granularity:

Case compatible (default) earlier later reject
Nonexistent (clock springs forward) shift forward + hint shift backward + hint shift forward + hint error nonexistent-time
Ambiguous (clock falls back) earlier occurrence + hint earlier + hint later + hint error ambiguous-time

The hint always shows the zone name and offset, for example “Time zone: India Standard Time (GMT+05:30)”.

All text uses textContent; no HTML parsing. CSP-safe.

No persistence, network access, or telemetry. When name is set, the hidden input carries ISO 8601: YYYY-MM-DD, or a UTC instant such as 2026-03-08T07:30:00.000Z.

Each edit recomputes only this instance: one parse, and up to 3 timezone offset lookups with cached Intl.DateTimeFormat instances. Budget: under 5 ms average per DateInput.create across 100 instances in headless Chromium.

100 instances per page in the performance test.

  • February 30 reports invalid-date immediately.
  • 02:30 on 2026-03-08 in America/New_York becomes 03:30 EDT with a hint under compatible, or an error under reject.
  • 01:30 on 2026-11-01 in America/New_York resolves to the EDT occurrence (05:30Z) under compatible.
  • Instants are displayed in the configured zone; for example 2026-12-31T20:00Z shows as 2027-01-01 01:30 in Asia/Kolkata.
  • Years 1 to 99 are supported without the Date.UTC 1900 mapping bug.
Code Category Cause
DATE_INPUT_LABEL configuration Missing label.
DATE_INPUT_TRAILING configuration trailing is not an element.
DATE_INPUT_VALUE_KIND configuration Value, min, or max type does not match the granularity.
CFG_INIT_ONLY configuration Changing granularity after creation.
Validation errors validation (validity.error) incomplete, invalid-date, value-missing, range-underflow, range-overflow, nonexistent-time, ambiguous-time.
  • No calendar popup; use Date Picker.
  • Gregorian calendar only; years 1 to 9999. Minute precision only.
  • Timezone rules come from the browser’s ICU data.
  • Manual screen-reader and user testing is pending.
  • Free-form localized text parsing.
  • Changing granularity after creation.