Input Date

A date field with a typeable value and a calendar button. Click the value to type. The calendar button opens the picker.

Usage

A composed control: InputGroup plus a calendar button that opens a Popover with the themed Calendar. Compose it inside a Field for the label and a11y wiring. Clicking the value places a caret. The calendar button (and Down Arrow) opens the popover.

Don't use the native <input type="date">: its picker can't be themed and differs per browser/OS. For a month grid with no field, use Calendar.

import { Field, FieldLabel } from '@epilot/spark-ui/field'
import { InputDate } from '@epilot/spark-ui/input-date'
function StartDateField() {
  const [value, setValue] = useState('')

  return (
    <Field>
      <FieldLabel>Start date</FieldLabel>
      <InputDate
        calendarLabel={t('openCalendar')}
        onValueChange={setValue}
        value={value}
      />
    </Field>
  )
}

Typing is owned by ictus inside Input Date. 4 becomes 04., a typed . / - commits a started group, and impossible second digits are ignored. A half-typed value stays in the field; onDateChange is undefined until the string is a complete, calendar-valid date. Surface a Field error on blur when the value is non-empty and unparseable.

calendarLabel is required. Input Date ships no English default for the button.

Pass separator (. or /) to match the app locale. Field order is day-month-year. Pass Calendar options such as locale through calendarProps. Opening the popover shows the month of the parsed value, or today if the field is empty.

On mobile, keep this click split if you swap the popover for a Drawer: type in the field, icon opens the drawer. Do not make the whole field the drawer trigger in the default usage.

For every Field / Input / InputGroup combination and state side by side, see the Field Matrix.

Examples

Picker only

When the job is picking a near-term day and weekday context matters more than typing, set pickerOnly. Click the value or the calendar button to open the popover. The field uses cursor-pointer so it does not look like a caret input. Do not combine an editable input with click-to-open: pickerOnly is what switches that rule.

Disabled dates

Pass DayPicker matchers through calendarProps.disabled to gray out days that must not be chosen. A meter reading cannot be in the future, so disable every day after today with { after: today }. Today stays selectable. This example uses pickerOnly so the field opens the calendar on click.

Meter readings cannot be in the future. Days after today are disabled in the calendar.

API Reference

InputDate

Native <input> attributes except value, defaultValue, onChange, readOnly, and type. className merges onto the InputGroup chrome. Use pickerOnly instead of readOnly.

PropTypeDefaultDescription
calendarLabelstring—Accessible name of the calendar button and of the open popover. Required; no built-in copy.
valuestring—Controlled masked string (DD.MM.YYYY with the configured separator).
defaultValuestring""Uncontrolled initial masked string.
onValueChange(value: string) => void—Fires on every accepted keystroke and on a calendar pick.
onDateChange(date: Date | undefined) => void—Parsed local Date when the string is complete and valid, else undefined.
pickerOnlybooleanfalsePicker-only: click the value opens the calendar. Typing is off. Sets native readOnly on the input.
separatorstring"."Written between day, month, and year. Typed . / - all commit this character.
placeholderstringDD.MM.YYYYShown while the value is empty. The default follows separator.
openboolean—Controlled popover visibility.
defaultOpenbooleanfalseUncontrolled initial popover visibility.
onOpenChange(open: boolean) => void—Fires when the popover opens or closes.
calendarPropsOmit<CalendarProps, "mode" | "selected" | "onSelect">—Passed to Calendar (locale, disabled, …). Opening shows the parsed value's month, or today if empty. A passed month overrides that.
disabledboolean—Disables the input and the calendar button.
classNamestring—Merges with the InputGroup box styles.

A calendar pick writes formatDate into the same string onValueChange receives. Do not pass onChange: keystrokes are handled on keydown.

Accessibility

Key / pointerAction
Click the valuePlaces a caret. Does not open the popover. With pickerOnly, opens the popover.
Calendar buttonOpens the popover. Stays in the tab order.
Down Arrow, Alt+Down ArrowOpens the popover from the focused input.
EscapeCloses the popover (Popover default).

Keep the calendar button in the tab order. Give calendarLabel a translated name such as "Open calendar".

On this page