Date input Documentation has not yet been reviewed by a human.
Use InputDate to enter a date by typing or choosing a day from a calendar.
Add time when the task also needs a time of day. Use Calendar
directly when the month grid should stay visible without a field.
Render InputDate and Calendar only on the client. Their current date and locale
can differ between server and browser rendering. In Astro, use client:only.
See Server and worker rendering for
setup guidance.
Playground
The date field
Enter a date and press Enter or leave the field to confirm it. InputDate accepts the locale’s date order, month names, and dates without separators, then formats the result. An unrecognized entry stays visible and marks the field invalid so it can be corrected.
Select the field to open its calendar while keeping focus in the text. Press ↓ to open the calendar and focus a day. Press Esc to close it and return focus to the field. While you type, the calendar previews recognized dates. Pressing Enter confirms the date and closes the calendar. An unrecognized entry keeps the calendar open.
<InputDate label="Due date" defaultValue="2026-06-15" onValueChange={(v) => save(v)} />Set locale to choose the date format. For example, 06/07/2026 means June 7
in en-US and July 6 in de-DE. The placeholder shows the expected format.
Use min and max to limit both typed dates and calendar choices.
<InputDate label="US English" locale="en-US" defaultValue="2026-06-15" /><InputDate label="German" locale="de-DE" defaultValue="2026-06-15" />Pass time to add a time field and confirmation button to the calendar.
Choosing a day keeps the calendar open so the time can be entered before
confirming. The clock follows the locale. Use hour12 to override it.
You can also type a date and time together, such as 06/15/2026 2:30pm or
06/15/2026 14:30. In a 12-hour time field, entering 18 converts to 6 PM.
{/* `size` scales the calendar, the time inputs, the AM/PM toggle, and the buttons together. */}<InputDate size="small" label="Small" time defaultValue="2026-06-15T09:00" /><InputDate size="medium" label="Medium" time defaultValue="2026-06-15T09:00" /><InputDate size="large" label="Large" time defaultValue="2026-06-15T09:00" />Manage the value
Use defaultValue for an initial date, or pair value with onValueChange
to control it. InputDate reports an ISO string: YYYY-MM-DD, or
YYYY-MM-DDTHH:mm with time. An empty field reports ''. Add name to
submit that value with a form.
const [date, setDate] = useState('2026-06-15')
<InputDate label="Due date" name="due-date" value={date} onValueChange={setDate} /> InputDate props
| Prop | Type | Default | Description |
|---|---|---|---|
| value? | string | — | Controlled value — ISO YYYY-MM-DD (or YYYY-MM-DDTHH:mm with time), ''
for empty. Pair with onValueChange; the field and calendar follow it and a
pick only requests a change. |
| defaultValue? | string | — | Initial value for the uncontrolled case. |
| min? | string | — | Earliest selectable date (ISO). Earlier days disable, and a typed date before it stays uncommitted. |
| max? | string | — | Latest selectable date (ISO). |
| locale? | string | navigator.language | BCP-47 locale driving the display format, the placeholder mask, parsing order, and the calendar. |
| name? | string | — | Form field name — the ISO value submits under this key. |
| size? | smallmediumlarge | medium | Field size. Also sizes the calendar and the time row. |
| disabled? | boolean | — | Disable the field and the calendar. |
| label? | ReactNode | — | Field label, above the control. |
| hint? | ReactNode | — | Helper text under the field. Replaced by a format hint while the entry is unrecognized. |
| placeholder? | string | the locale's format mask (e.g. `MM/DD/YYYY`, `MM/DD/YYYY HH:MM` with `time`) | Placeholder shown when empty. |
| status? | neutralbrandinfosuccesswarningcritical | neutral | Validation/feedback tone. An unrecognized entry forces critical until fixed. |
| round? | booleannumberstring | — | Round the field corners — true for fully round, or a number / CSS length. |
| placement? | leftrightbottomtopbottom-startbottom-endtop-starttop-endright-startright-endleft-startleft-end | bottom-start | Preferred placement of the calendar menu relative to the field. Same values as
Menu; it auto-flips and clamps when space runs out. |
| offset? | number | 4 | Gap in pixels between the field and the calendar menu. |
| clearable? | boolean | — | Show a clear button once the field has a value. |
| icon? | falseIconShape | calendar-days | Leading icon at the start of the field — the calendar affordance. Pass
another shape to change it, or false to drop it. |
| time? | boolean | — | Include a time. The value becomes ISO YYYY-MM-DDTHH:mm, the field parses a
trailing time after a space (06/15/2026 14:30, … 2:30pm), and the menu
shows a time row (hours : minutes, an AM/PM toggle in 12-hour locales, then a
Done button) under the calendar. Picking a day keeps the menu open so you can
set the time. |
| hour12? | boolean | — | Force the time cycle when time is on: true for 12-hour (AM/PM), false
for 24-hour. Omit to follow the locale (en-US → 12-hour, most others → 24). |
| onValueChange? | (value, attrs) => void | — | Fired after the value resolves (a recognized entry, a calendar pick, a time
change, or a clear), with the new ISO value ('' when cleared) and a
{ value, name } snapshot. An unrecognized entry does not fire it. |
Inherited props (className, id, slot, style, tabIndex, title)
| Prop | Type | Default | Description |
|---|---|---|---|
| className? | string | — | CSS class on the component's root element (merged with the component's own
classes). Use it directly for layout and positioning — grid/flex placement,
margins, alignment — rather than wrapping the component in a <div>/<span>. |
| id? | string | — | HTML id attribute. |
| slot? | string | — | Assigns the element to a named <slot> of a parent web component (e.g.
slot="header" inside a <Dialog>, slot="footer" inside a <Dialog>). |
| style? | CSSProperties | — | Inline styles on the component's root element. Set layout/positioning here
(or via className) directly on the component instead of adding a wrapper. |
| tabIndex? | number | — | Tab order. Set to -1 to skip the element when tabbing. |
| title? | string | — | HTML title attribute — native browser tooltip on hover. |
Plus every standard DOM event handler (onClick,
onFocus, onKeyDown, …) and any
data-* or aria-* attribute — forwarded as-is to
the underlying <a-*> element.
Calendar
Use Calendar for an inline date picker, such as a booking form with a month always in view. It provides day selection, month navigation, keyboard access, and form submission.
Like InputDate, Calendar must render only on the client. The examples use
Astro’s client:only directive.
Selecting a date
Select a day, or focus it and press Enter or Space. The selected day has a brand-colored fill and ring. Today’s date has a subtle fill when it is not selected.
<Calendar defaultValue="2026-06-12" />Size
size scales the whole calendar: the day cells, the prev/next chevrons, and the
weekday and month-heading type. It follows Button’s small / medium (default) /
large scale, with day-cell heights of 24 / 28 / 32px.
<Calendar size="small" defaultValue="2026-06-28" /><Calendar defaultValue="2026-06-28" /> {/* medium (default) */}<Calendar size="large" defaultValue="2026-06-28" />Range
min and max (ISO strings) bound the selectable range. Days outside it render
disabled and skip keyboard focus, and the prev/next arrows stop at the range edge.
The jump menu adapts to how far the range reaches.
min / max: the jump menu lists today ±3 years, each a submenu of its months. <Calendar size="small" defaultValue="2026-06-15" /><Calendar size="small" defaultValue="2026-06-15" min="2026-06-08" max="2027-06-24" /><Calendar size="small" defaultValue="2026-06-15" min="2026-03-01" max="2026-11-30" /><Calendar size="small" defaultValue="2026-06-15" min="2026-06-08" max="2026-06-24" />Locale
Calendar uses the browser’s locale by default. Pass a locale tag such as
en-US, fr-FR, or ja-JP to choose the language and first day of the week.
<Calendar defaultValue="2026-06-28" locale="en-US" /> {/* week starts Sunday */}<Calendar defaultValue="2026-06-28" locale="fr-FR" /> {/* week starts Monday */}<Calendar defaultValue="2026-06-28" locale="ja-JP" />Controlled
Uncontrolled by default: pass defaultValue and read the date from onValueChange
or at form submit. Make it controlled with value + onStateChange to drive it
from your store. The grid then follows value, and a pick only requests a change:
answer by updating value, reject by doing nothing.
const [date, setDate] = useState('2026-06-28')
<Calendar value={date} onStateChange={(_e, { next }) => setDate(next ?? '')}/>onStateChange fires before the element applies, with (event, { next, prev, reason })
where next / prev are ISO strings. For a 'user' pick, event.preventDefault()
vetoes it (uncontrolled). A controlled calendar with no onStateChange is read-only.
Disabled
disabled dims the whole calendar and removes it from interaction.
<Calendar defaultValue="2026-06-28" disabled />Forms
Add name to submit the selected ISO date with a form. An uncontrolled Calendar
returns to defaultValue on form reset. For a controlled Calendar, handle the
reset request in onStateChange and update value as needed.
<form> <Calendar name="due-date" defaultValue="2026-06-28" /></form>Accessibility
InputDate identifies its calendar as a dialog associated with the field. Opening it with ↓ moves focus into the calendar. Closing it with Esc returns focus to the field.
Calendar announces the displayed month and gives each day its full date, including the weekday. Screen readers can identify the selected day and today’s date. The day grid has one Tab stop, and changing months announces the new month.
| Key | Moves focus |
|---|---|
| ← / → | by one day |
| ↑ / ↓ | by one week |
| Home / End | to the start / end of the week |
| PageUp / PageDown | by one month |
| Shift + PageUp / PageDown | by one year |
| Enter / Space | select the focused day |
Customization
Use the InputDate and Calendar wrappers for the complete date-entry interface.
For custom calendar rendering, buildMonth supplies localized weekday headers
and day records with ISO values, accessible labels, and selection and range
states. Your application supplies rendering and navigation.
Build it from elements
InputDate combines Input, Menu, and Calendar. There is no separate InputDate host element. Recreating it requires text parsing, date formatting, popup behavior, and focus management. For a form that can use the browser’s picker, consider Native HTML date input.
For a custom month grid, use <a-calendar> with day buttons marked
data-part="day-cell" and data-date="YYYY-MM-DD". It provides keyboard
navigation, selection requests, and form submission. Render the surrounding
month controls yourself and handle navigate when focus moves to another date.
buildMonth returns the month heading, weekdays, and day records. Pass min
and max to it when building a bounded grid, render out-of-range dates with
disabled, and limit your month controls to that range.
This example supplies previous and next month controls and a controlled selection:
<!-- `.calendar` scopes this example. Use an application selector instead. --><div class="calendar" style="display: inline-flex; flex-direction: column; gap: 6px"> <div style="display: flex; align-items: center"> <a-button role="button" tabindex="0" priority="tertiary" data-prev aria-label="Previous month"><a-icon shape="chevron-left" aria-hidden="true"></a-icon></a-button> <span data-heading style="flex: 1; text-align: center"></span> <a-button role="button" tabindex="0" priority="tertiary" data-next aria-label="Next month"><a-icon shape="chevron-right" aria-hidden="true"></a-icon></a-button> </div> <a-calendar role="group" name="date"></a-calendar></div><script type="module"> import '@antadesign/anta/elements' import { buildMonth, parseISODate } from '@antadesign/anta' import { Temporal } from 'temporal-polyfill'
const root = document.querySelector('.calendar') const grid = root.querySelector('a-calendar') const heading = root.querySelector('[data-heading]') let cursor = Temporal.Now.plainDateISO() grid.value = cursor.toString()
function focusDate(iso) { grid.querySelector(`[data-date="${iso}"]`)?.focus() }
function render() { const month = buildMonth({ anchor: cursor, locale: navigator.language, selected: parseISODate(grid.value), }) heading.textContent = month.heading grid.setAttribute('aria-label', month.heading) grid.replaceChildren() for (const weekday of month.weekdays) { const label = Object.assign(document.createElement('span'), { textContent: weekday.narrow }) label.setAttribute('data-part', 'weekday') label.setAttribute('aria-hidden', 'true') grid.append(label) } for (const day of month.weeks.flat()) { const button = document.createElement('a-button') const label = Object.assign(document.createElement('a-button-label'), { textContent: String(day.day) }) button.append(label) button.setAttribute('role', 'button') button.setAttribute('priority', day.today && !day.selected ? 'secondary' : 'tertiary') button.setAttribute('data-part', 'day-cell') button.setAttribute('data-date', day.iso) button.setAttribute('aria-label', day.label) button.setAttribute('aria-pressed', String(day.selected)) button.tabIndex = day.iso === cursor.toString() ? 0 : -1 if (day.selected) { button.setAttribute('selected', '') button.setAttribute('tone', 'brand') } if (day.disabled) button.setAttribute('disabled', '') if (day.today) { button.setAttribute('data-today', '') button.setAttribute('aria-current', 'date') } if (day.outside) button.setAttribute('data-outside', '') grid.append(button) } }
root.querySelector('[data-prev]').addEventListener('click', () => { cursor = cursor.subtract({ months: 1 }) render() }) root.querySelector('[data-next]').addEventListener('click', () => { cursor = cursor.add({ months: 1 }) render() }) grid.addEventListener('statechange', (event) => { grid.value = event.detail.next ?? '' cursor = parseISODate(grid.value) ?? cursor render() focusDate(cursor.toString()) }) grid.addEventListener('navigate', (event) => { cursor = parseISODate(event.detail.date) ?? cursor render() focusDate(cursor.toString()) }) render()</script>Use the Calendar wrapper when you also need its year/month jump menu and range-aware controls.
Raw Calendar value and form API
Use value for controlled selection or defaultvalue for an uncontrolled
initial and reset date. The .value property returns the applied ISO date, or
null when empty. The .defaultValue property returns the authored reset date,
or null when unset.
Assigning a string to .value supplies controlled input. An empty value=""
keeps the calendar controlled and empty. Remove value, or assign null or
undefined to .value, to release control while retaining the applied date.
Uncontrolled picks, reset, and restoration leave those input attributes unchanged.
Accept controlled picks from statechange by updating value. change reports
applied selection. navigate requests a new focus date. The application renders
the requested month and focuses that day. Author the month label and each day
button’s accessible name. Calendar does not generate those labels.
For Preact, prefer the Calendar wrapper. Raw <a-calendar value={...}> bindings
can retain the old value when assigned undefined, or write value="" when the
prop is omitted. Release a raw instance by removing its value attribute or
assigning null to .value.
Calendar props
| Prop | Type | Default | Description |
|---|---|---|---|
| value? | string | — | Controlled selected date — ISO YYYY-MM-DD. When provided, the application
controls selection: the grid follows this prop and a pick only requests a change via
onStateChange. Leave undefined for uncontrolled. |
| defaultValue? | string | — | Initial selected date for the uncontrolled case (ISO YYYY-MM-DD). |
| min? | string | — | Earliest selectable date (ISO YYYY-MM-DD) — earlier days render disabled. |
| max? | string | — | Latest selectable date (ISO YYYY-MM-DD) — later days render disabled. |
| locale? | string | navigator.language | BCP-47 locale tag driving first-day-of-week, weekday, and month names. |
| name? | string | — | Form field name — the selected ISO date submits under this key. |
| size? | smallmediumlarge | 'medium' | Size of the whole calendar — scales the day cells, the chevrons, and the
weekday / month-heading type together (uses Button's small / medium /
large scale). |
| disabled? | boolean | — | Disable the whole calendar (not focusable or selectable). |
| focusSignal? | number | — | Move keyboard focus onto the active day. Change this to a new value (e.g.
increment a counter) to focus the cursor cell — InputDate bumps it when
the calendar is opened from the field by keyboard (ArrowDown), so focus
lands in the grid. The initial value never focuses; only a change does. |
| aria-label? | string | — | Accessible name for the grid (defaults to the visible month heading). |
| onStateChange? | (event, detail) => void | — | Fired whenever the selection changes — event-first. detail is
{ next, prev, reason }: next / prev are ISO date strings (null = none);
reason is 'user' | 'reset' | 'restore'. A 'user' pick fires before
applying and is cancelable — event.preventDefault() vetoes it
(uncontrolled), or in controlled mode answer by updating value. 'reset' /
'restore' are not cancelable. |
| onChange? | (event) => void | — | Fired after the selection changes (post-apply). Not cancelable; for a
controlled calendar it fires once you've updated value. |
| onValueChange? | (event, attrs) => void | — | Like onChange, but with a { value, name } snapshot as the second argument,
matching Input. |
Inherited props (className, id, slot, style, tabIndex, title)
| Prop | Type | Default | Description |
|---|---|---|---|
| className? | string | — | CSS class on the component's root element (merged with the component's own
classes). Use it directly for layout and positioning — grid/flex placement,
margins, alignment — rather than wrapping the component in a <div>/<span>. |
| id? | string | — | HTML id attribute. |
| slot? | string | — | Assigns the element to a named <slot> of a parent web component (e.g.
slot="header" inside a <Dialog>, slot="footer" inside a <Dialog>). |
| style? | CSSProperties | — | Inline styles on the component's root element. Set layout/positioning here
(or via className) directly on the component instead of adding a wrapper. |
| tabIndex? | number | — | Tab order. Set to -1 to skip the element when tabbing. |
| title? | string | — | HTML title attribute — native browser tooltip on hover. |
Plus every standard DOM event handler (onClick,
onFocus, onKeyDown, …) and any
data-* or aria-* attribute — forwarded as-is to
the underlying <a-*> element.
Web Component
Use a native date input when the browser’s picker fits your form. To build a custom picker without JSX, see Build it from elements.
Native HTML date input
Add data-anta to a date, datetime-local, month, time, or week input.
Nothing else is required: Anta styles the field while the browser keeps its picker,
icon, validation, and keyboard model. The picker itself and its date/time
formatting remain browser- and OS-owned.
data-anta-size, round, and a custom-color tone use the matching Input
field treatments.
<!-- `data-anta` styles the field, not the native picker. --><input data-anta type="date" name="due-date" value="2026-06-15"><input data-anta type="datetime-local" name="starts-at" value="2026-06-15T09:00"><input data-anta type="month" name="billing-month" value="2026-06"><input data-anta type="time" name="reminder-at" value="09:00"><input data-anta type="week" name="sprint-week" value="2026-W25"> Styling
Use ordinary CSS to style the calendar and its day buttons. className applies
to the outer .anta-calendar container. Unlayered consumer rules override Anta’s
defaults. Replace the example classes with your own selectors.
Set --calendar-cell-width and --calendar-cell-height to make day targets
larger, then use border-radius to shape them:
/* Bigger, circular day cells. `className` lands on the outer .anta-calendar shell; `--calendar-cell-width` / `--calendar-cell-height` drive the grid track and the cell box (inherited down), and you target the day Buttons directly. */.anta-calendar.roomy { --calendar-cell-width: 40px; --calendar-cell-height: 40px; }.anta-calendar.roomy a-button[data-part="day-cell"] { border-radius: 50%; }Each day is a <a-button data-part="day-cell" data-date="YYYY-MM-DD">, so a
specific date is addressable by its data-date: tint it, or hang an event marker
off a ::after (give the cell position: relative first). Below, three days carry a
brand dot and one is flagged in the critical color.
/* Day cells are `<a-button data-part="day-cell" data-date="YYYY-MM-DD">`. Give them a positioning context, dot event days with a `::after`, and tint a date's text. */.anta-calendar.events a-button[data-part="day-cell"] { position: relative; }.anta-calendar.events a-button[data-part="day-cell"]:is( [data-date="2026-06-05"], [data-date="2026-06-12"], [data-date="2026-06-20"])::after { content: ""; position: absolute; inset-block-end: 3px; inset-inline-start: 50%; inline-size: 4px; block-size: 4px; transform: translateX(-50%); border-radius: 999px; background: var(--text-2-brand);}.anta-calendar.events a-button[data-part="day-cell"][data-date="2026-06-25"] { color: var(--text-2-critical); font-weight: 600;}For a custom month layout, use the exported buildMonth and firstDayOfWeek
helpers. See Build it from elements.