---
title: Date Field
description: Date fields capture a single calendar date with locale-aware formatting and an optional calendar popup for pointer input.
category: Forms
---
import { meta as DateFieldMeta, Default, WithCalendar } from '@/content/stories/date-field';
import Canvas from '@/components/component-docs/canvas';
import Demo from '@/components/component-docs/demo';
export const config = {
dependencies: {
components: [Canvas, Demo],
scripts: [
'../../components/component-docs/demo.script.tsx',
'../../components/component-docs/canvas.script.tsx',
'../../components/component-docs/controls.script.tsx',
],
},
};
# Date Field
Date fields capture a single calendar date with locale-ordered editable segments and an optional calendar popup for pointer input.
## Try it
## Usage
Compose the segment input, calendar trigger, popup, and calendar as children of `RuiDateField`. When no children are supplied, `RuiDateField` renders this same composition for you. Bind `value` as an ISO `YYYY-MM-DD` string. For the segment editor without a calendar popup, use Date Input.
```tsx
import {
RuiDateField,
RuiDateFieldCalendar,
RuiDateFieldControl,
RuiDateFieldInput,
RuiDateFieldPopover,
RuiDateFieldToggle,
} from '@ecopages/radiant-ui/date-field';
import { RuiField } from '@ecopages/radiant-ui/field';
import { RuiLabel } from '@ecopages/radiant-ui/label';
Start date
```
## Custom markup
```tsx
import '@ecopages/radiant-ui/date-field';
import '@ecopages/radiant-ui/date-input';
import '@ecopages/radiant-ui/calendar';
```
## Calendar input
Use the calendar button to choose a date instead of typing. When the popup opens, focus moves to the selected date or the first available date. This example uses a two-month popup for dates near a month boundary.
## Segment entry
Each month, day, and year unit is focusable and editable with the keyboard or a numeric keypad. Typing replaces the focused unit; arrow keys move between units or increment values.
## Bound the range
Set `min` and `max` to prevent invalid bookings. The embedded calendar inherits the same constraints.
## Theming
Date Field surfaces map to **semantic surface roles**, never Tailwind palette steps:
| Part | CSS roles |
| --- | --- |
| Control group (`rui-date-field__group`) | `border`, `background`, `radius-control`; `focus-ring` ring on focus-within |
| Input text | `on-background`, `--text-control`, `--space-control-*` |
| Segment placeholder | `on-surface` + `opacity-muted` |
| Disabled | `opacity-disabled` |
| Invalid (`aria-invalid`) | `error` border |
| Popup (`rui-date-field__popover`) | `popover` surface + `shadow-overlay` (via `rui-popover`) |
Geometry shares control tokens (`--size-control-*`, `--radius-control`, `--space-control-*`) with `RuiInput` and `RuiButton` so form rows align. Override at the theme layer, not in component CSS.
## API
`RuiDateField` is a custom element (``) that coordinates its light-DOM input, toggle button, and calendar popover. It is not form-associated; `name` lands on the nested `rui-date-input`.
### Attributes
| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | `''` | Canonical ISO `YYYY-MM-DD` value. |
| `min` | `string` | `''` | Earliest selectable ISO date. |
| `max` | `string` | `''` | Latest selectable ISO date. |
| `disabled` | `boolean` | `false` | Disable the field and calendar. |
| `read-only` | `boolean` | `false` | Disable editing while keeping the value visible. |
| `label` | `string` | `''` | Accessible name when there is no associated `RuiLabel`. |
| `name` | `string` | `''` | Form field name on the nested `rui-date-input`. |
| `locale` | `string` | `''` | BCP 47 locale tag, or comma-separated fallback list. |
| `visible-months` | `number` | `1` | Month grids shown in the calendar popover. |
### Light-DOM contract
| Target | Required | Host writes | Author owns |
| --- | --- | --- | --- |
| `[data-date-field-input]` | yes | `value`, `name`, `locale`, `min`, `max`, `disabled`, `read-only` | nested `rui-date-input` |
| `[data-date-field-trigger]` | yes | `aria-expanded`, `disabled` | toggle (`data-ref="trigger"`) |
| `[data-date-field-popover]` | yes | `hidden` | popup (`data-ref="popover"`) |
| `[data-date-field-calendar]` | yes | `selection-mode`, `value`, `min`, `max`, … | nested `rui-calendar` |
Nested host: `rui-calendar` at `[data-date-field-calendar]` — parent queries `[data-calendar-day]` inside it.
### Events
| Event | Detail | Description |
| --- | --- | --- |
| `rui-change` | `{ value }` | Fired when a valid date is committed (typing or calendar pick). |
### View helpers
| Component | Target stamped | Notes |
| --- | --- | --- |
| `RuiDateFieldControl` | — | Bordered control row |
| `RuiDateFieldInput` | `[data-date-field-input]` | Nested `rui-date-input` segment editor |
| `RuiDateFieldToggle` | `[data-date-field-trigger]` | Opens calendar popup |
| `RuiDateFieldPopover` | `[data-date-field-popover]` | Popup shell |
| `RuiDateFieldCalendar` | `[data-date-field-calendar]` | Synced `rui-calendar` |
### CSS classes
Public BEM classes on the composed light-DOM surface (documented via `@cssclass` on `RuiDateField`):
| Class | Description |
| --- | --- |
| `.rui-date-field` | Root surface. |
| `.rui-date-field__group` | Bordered control-height row wrapping input and toggle. |
| `.rui-date-field__input` | Host for nested `rui-date-input`. |
| `.rui-date-field__popover` | Calendar popup shell (`rui-popover` / `rui-floating`). |
### Theme roles
| Part | CSS variables consumed |
| --- | --- |
| Control group | `--border`, `--background`, `--radius-control`, `--focus-ring` |
| Input text | `--on-background`, `--text-control`, `--space-control-x`, `--space-control-y` |
| Placeholder | `--on-surface`, `--opacity-muted` |
| Disabled | `--opacity-disabled` |
| Invalid | `--error` |
| Popup | `--shadow-overlay` (via `rui-popover`) |
## Accessibility
- Pair every date field with a visible `RuiLabel` or `label` / `aria-label` on the segment group.
- Invalid dates should surface through `RuiField` error text, not color alone.
- Segments expose spinbutton semantics (or textbox on iOS VoiceOver) with `inputmode="numeric"` for touch keyboards.
- The calendar button is optional; focus the field to type, or open the popup to pick from the grid.
- The trigger opens the popup and moves focus to the selected date or first available date; arrow keys move between days, Page Up / Page Down change months, and Escape closes the popup.