Skip to content

Date Input ​

Shared label and supporting-text behaviour with catnip-input is summarised on Inputs overview.

catnip-input-date ​

Props ​

Value & mode ​

PropTypeDefaultOptionsDescription
modelValueCatnipInputDateModelValuenull—Committed value; model-value in HTML / .modelValue in frameworks.
modestring"single"single, rangeSingle date/datetime or range selection.
showTimebooleanfalse—Adds a time input and serializes endpoints as YYYY-MM-DDTHH:mm. Shows the panel action footer.
showPresetsbooleanfalse—Range-only. Shows the preset sidebar (Today, Last 7 days, Custom range, …). Ignored in single mode.
periodPresetsCatnipInputDatePeriodPresetConfig[][]Built-in preset idsSubset, reorder, or relabel built-in range presets. Empty uses the full built-in list.
showActionsbooleanfalse—Forces the panel Reset / Cancel / Apply row. Also shown automatically for showTime and showPresets.
openboolean——Controlled panel state. Pair with open-change.

Date constraints ​

PropTypeDefaultOptionsDescription
minstring""YYYY-MM-DDEarliest selectable date.
maxstring""YYYY-MM-DDLatest selectable date.
disabledDatesstring[][]YYYY-MM-DD valuesUnavailable days. They stay focusable in the calendar and are announced as unavailable.
maxRangeDaysnumber—Positive integerRange-only inclusive maximum number of calendar days. 0 / unset means no range-length limit.
firstDayOfWeeknumber10 through 6First day in the calendar grid; 0 is Sunday, 1 is Monday.
localestring""BCP 47 localeLocale for month and weekday labels. Empty uses the browser locale.

Field presentation ​

PropTypeDefaultOptionsDescription
labelstring""—Visible field label when the label slot is empty.
startLabelstring""—Vertical range+time panel: From field label. Defaults to locale From.
endLabelstring""—Vertical range+time panel: To field label. Defaults to locale To.
placeholderstring""—Placeholder for the combined trigger. Empty uses the active display format (YYYY-MM-DD — YYYY-MM-DD in range mode).
displayFormatstring"YYYY-MM-DD"Day.js format tokensVisible date-only input format. Parsing also accepts this format; emitted values stay canonical.
displayDateTimeFormatstring"YYYY-MM-DD, HH:mm"Day.js format tokensVisible datetime input format when the typed value includes time. Parsing also accepts this format; emitted values stay canonical.
panelOrientation"horizontal" | "vertical""horizontal"horizontal, verticalHorizontal pages one month (two side-by-side in range). Vertical stacks a scrollable month list. Range horizontal switches to vertical automatically below 800px.
panelPlacement"top" | "bottom""bottom"top, bottomPreferred panel placement. Flips when there is insufficient space.
panelAlign"start" | "end""start"start, endCross-axis alignment of the panel relative to the trigger.
showClearButtonbooleantrue—Shows an inline reset icon inside the trigger when the field has a value.
clearButtonAriaLabelstring""—Accessible label for the inline reset icon; defaults to bundled inputDate.clear.
supportingTextSupportingTextProp""—One or more helper or validation messages. Each object requires text; intent accepts neutral, danger, warning, or success, and icon accepts a Catnip icon name. See supporting-text examples.
size"s" | "m" | "l""m"s, m, lDimensions and typography.
intent"neutral" | "danger" | "warning" | "success""neutral"neutral, danger, warning, successSemantic state applied to field and supporting-text styling; danger sets aria-invalid on the date control.
disabledbooleanfalse—Disables the trigger, calendar, and panel actions.
readonlybooleanfalse—Prevents editing and panel interaction.
requiredbooleanfalse—Native required state and label marker.
hideLabelbooleanfalse—Hides the built-in label row.
inputDateAriaLabelstring""—aria-label when there is no visible label.
ariaDescribedbystring""—Extra id values merged into aria-describedby alongside generated supporting-text ids.

Advanced ​

PropTypeDefaultOptionsDescription
inputDateIdstring""—DOM id for the input. Auto-generated when omitted.
namestring""—Native name for form submission.
inputDateAutofocusbooleanfalse—Forwards native autofocus to the text input.
optionalbooleanfalse—When true and not required, shows the localized optional hint.
optionalTextstring""—Overrides the localized optional hint (HTML: optional-text).
infostring""—Info tooltip beside the label; when non-empty, it wins over the label.suffix slot.
alignment"left" | "center" | "right""left"left, center, rightHorizontal alignment of the field label block.
requiredMarkerstring"*"—Visual marker for required fields (HTML: required-marker).
requiredScreenReaderTextstring""—Optional screen-reader supplement; it does not replace required on the control (HTML: required-screen-reader-text).
testSelectorsTestSelectorsPropSee Test Selectors—Overrides stable data-test values.

Values ​

Modeshow-timeshow-presetsValue
Singlefalse—"YYYY-MM-DD"
Singletrue—"YYYY-MM-DDTHH:mm"
Rangefalsefalse{ start?: "YYYY-MM-DD"; end?: "YYYY-MM-DD" }
Rangetruefalse{ start?: "YYYY-MM-DDTHH:mm"; end?: "YYYY-MM-DDTHH:mm" }
Range—true{ start?: string; end?: string; preset?: string }

Built-in preset ids: today, yesterday, last-7-days, last-30-days, last-90-days, this-month, last-month, all-time, custom.

Display formats affect only the text shown in the input. Model values, events, constraints, and form serialization continue to use the canonical value formats above. Range endpoints in the trigger are separated with an em dash (—). The trigger fills its container and its text field is a single line: a value that doesn't fit scrolls inside the field.

Typed input and validation ​

InputAccepted textHint in aria-describedby
Trigger fieldAny text; parsed with display-format / display-date-time-format and locale, then forgivingly (see below).inputDate.formatHint with the field format.
Time box (show-time)Digits and : only, up to 5 characters. 930, 9:30, and 0930 expand to 09:30 on blur.inputDate.formatHint with inputDate.timeFormat.
From / To fields (vertical range + time)Any text; parsed with display-date-time-format. Emptying one clears that date, so Apply stays disabled.inputDate.formatHint with that format.
  • Forgiving dates: when the text doesn't match the display formats, the field still accepts:

    • ., /, -, commas, or spaces between day, month, and year, in any amount (voice input's extra spaces don't matter);
    • digits without separators, read in the display format's order (27031990 for DD.MM.YYYY, 19900327 for YYYY-MM-DD), with leading zeros; a format with a two-digit year also takes six digits (102226 for M/D/YY);
    • missing leading zeros (7.3.1990);
    • month names or abbreviations in locale or English (27 March 1990, 27 mar 1990);
    • an optional HH:mm after the date.

    A four-digit year first always reads as year, month, day. A two-digit year is read only when the display format has one (YY), from the position the format puts it in, with the same century rule as Day.js (69–99 → 1900s, 00–68 → 2000s). With the year last, day and month follow the display format, or the locale's order when the format starts with the year. A "month" above 12 is read as the day. Range text splits at the em or en dash, or at a spaced hyphen that leaves a date on each side. On blur the value is rewritten in the display format.

  • Number pad: a single date without time whose display-format is all digits and separators (no month names, ordinals, or [literal] text) sets inputmode="numeric", so phones show a number pad. Some number pads (iOS) have no separators; digits without separators still parse when every part is typed with its leading zeros. Ranges and show-time keep the full keyboard because they need a dash, space, or colon. inputmode doesn't limit what can be typed.

  • Text that doesn't parse is never committed and never cleared. On blur it stays in place, gets aria-invalid="true" and the danger border, and shows inputDate.invalidFormat with an error icon (below the trigger as supporting text, or below the panel input). The flag clears as soon as the text parses again.

  • Consumer supporting-text still renders; the format message is appended after it. Domain rules such as required dates stay consumer-owned through intent and supporting-text.

  • Apply is enabled once the dates are complete. If a typed value is invalid, Apply flags every invalid input and moves focus to the first one instead of submitting.

  • Override inputDate.formatHint ("Format: {format}"), inputDate.invalidFormat ("Use the format {format}"), and inputDate.timeFormat ("HH:mm, 24-hour") through registerTranslate.

Events ​

NamePayloadDescription
update:modelValuestring | { start?: string; end?: string; preset?: string } | nullCommitted value changed. Not emitted when the value is unchanged.
open-changebooleanPanel open state changed (true / false). Use @open-change.
submitstring | { start?: string; end?: string; preset?: string }Draft value applied from the panel action row.
cancel—Cancel, or Escape while the panel has Apply, discarded the draft and closed the panel.
clear—Reset or inline clear reset the value.
close—The panel closed, for any reason. Not emitted when it was already closed.

Keyboard ​

Field ​

KeyBehaviour
Arrow Down / Alt + Arrow DownOpens the panel and moves focus into it: the selected preset (or the first one), otherwise the active day.
EnterCommits the typed value and closes the panel; with Apply in the panel, works as Apply.
TabCloses the panel and moves on, like any combobox.
EscapeCloses the panel.

Focusing the field never opens the panel; a click opens it and keeps focus in the field. Each time the panel opens it shows the selected date (the range start, or today when nothing is selected), not the month browsed last time.

Panel ​

KeyBehaviour
Tab / Shift + TabMoves between the panel's controls; focus wraps inside the panel.
EscapeCloses the panel and returns focus to the field. With Apply, also discards the draft like Cancel.

Focus returns to the field after every close except a click outside. A visually hidden Close button (not in the Tab order) is added when the panel has no Cancel, so touch screen reader users can dismiss it.

Presets ​

KeyBehaviour
Arrow Up / Arrow DownPrevious / next preset.
Home / EndFirst / last preset.
Enter / SpacePick the focused preset.

The list has one Tab stop: the focused, otherwise selected, preset.

Calendar ​

KeyBehaviour
Arrow Left / RightMove active day backward / forward.
Arrow Up / DownMove active day by one week.
Home / EndMove to the start / end of the active week.
PageUp / PageDownMove to the previous / next month.
Shift + PageUp / Shift + PageDownMove to the same month in the previous / next year.
Enter / SpaceSelect active date.

Arrow keys stop at min and max. Unavailable days (disabled-dates, or past max-range-days while picking the end) can be focused and are announced as unavailable, but not selected. The calendar has one Tab stop, on the active day, even with two months shown.

The month/year header button opens a year grid. In range mode it also opens a month grid: years on the left and months on the right in the horizontal dual-month panel, or years above months in the vertical stack. Selecting a year updates the month grid; selecting a month returns to the day calendars. Single-date mode still uses the year grid only. In the year grid, arrow keys move between years, PageUp / PageDown move between year ranges, and Enter / Space selects the active year. In the month grid, arrows move between months and Enter / Space selects the active month.

Accessibility tree ​

PartSemantics
Field<input role="combobox"> with aria-haspopup="dialog", aria-expanded, aria-autocomplete="none", and aria-controls while open.
Panelrole="dialog" named "{label}, Choose date" (or "Choose dates" in range mode). aria-modal="true" only while focus is inside.
Month<table role="grid"> named by month and year; weekday column headers carry the full weekday name; each day is a button in a role="gridcell".
Day namesFull date, then as applicable: "today", "unavailable", "selected", "start of selected range", "end of selected range". Today also has aria-current="date".
Live regionPolite. Announces "Start date {date}. Choose an end date.", "Selected range: {range}", and the month shown after the previous / next buttons.
Preset fieldWhile a named preset is shown, its dates are added to the field's description; while the field has focus it shows the dates and describes "Preset: {name}".

Override the new strings through registerTranslate: inputDate.chooseDate, inputDate.chooseDates, inputDate.close, inputDate.presetDescription, and the shared calendar keys calendar.today ("today"), calendar.selected ("selected"), calendar.rangeStart ("start of selected range"), calendar.rangeEnd ("end of selected range"), calendar.unavailable ("unavailable"), calendar.startChosen ("Start date {date}. Choose an end date."), calendar.rangeSelected ("Selected range: {range}"), and calendar.dateSelected ("Selected: {date}"). Existing inputDate.* keys for navigation (for example inputDate.previousMonth) still take precedence over their calendar.* equivalents.

Slots ​

NameDescription
labelCustom label content; falls back to label prop.
label.actionTrailing action in the label row.
label.suffixCustom label suffix; used only when info is empty.
startLabelVertical range+time panel: custom From label; falls back to startLabel prop / locale.
endLabelVertical range+time panel: custom To label; falls back to endLabel prop / locale.
valueSelected-value area inside the default trigger (calendar icon, clear, and chevron stay). Replaces the typeable field.
triggerFull trigger override — see Trigger slot below.

Trigger slot ​

When trigger is set, the default field shell is replaced. The slot is wrapped in an anchor used to position the calendar panel.

  • Include a focusable control (e.g. <button type="button">). Date applies aria-haspopup="dialog" and aria-expanded. It doesn't set aria-controls: the panel is inside the component's shadow root, which an ID reference from the light DOM can't reach.
  • Click toggles the panel. Enter / Space and ArrowDown open it and move focus in; Enter / Space close it again.
  • Prefer the value slot when you only need to customize the selected-date display.
  • If both are set, trigger wins and value is ignored.

Forms ​

The name you set on <catnip-input-date> participates in form serialization. Single mode submits the committed string value. Range mode serializes the committed object as JSON for form-associated custom element submission.

Test selectors ​

The panel and everything in it (days, presets, time inputs, actions) render inside the component's shadow root. Query them through element.shadowRoot or a selector engine that pierces open shadow roots: Playwright locators do by default; Cypress needs includeShadowDom: true.

AttributeDefaultApplies to
rootcatnip-input-dateField wrapper
controlcatnip-input-date-controlCombobox text field
valuecatnip-input-date-valueCustom value slot mount
clearButtoncatnip-input-date-clearInline reset button
chevroncatnip-input-date-chevronTrailing open/close chevron
previousButtoncatnip-input-date-previousPrevious month / year-range button
nextButtoncatnip-input-date-nextNext month / year-range button
viewTogglecatnip-input-date-view-toggleMonth/year header toggle
panelcatnip-input-date-panelCalendar dialog panel
presetscatnip-input-date-presetsRange preset list
presetcatnip-input-date-presetRange preset row
monthcatnip-input-date-monthMonth block in the panel
gridcatnip-input-date-gridCalendar grid
daycatnip-input-date-dayCalendar day button
yearGridcatnip-input-date-year-gridYear selection grid
yearcatnip-input-date-yearYear selection button
monthGridcatnip-input-date-month-gridRange month selection grid
monthNamecatnip-input-date-month-nameRange month selection button
timecatnip-input-date-timeOptional time section
singleTimeInputcatnip-input-date-time-inputSingle-date time input
startTimeInputcatnip-input-date-start-time-inputRange start time input
endTimeInputcatnip-input-date-end-time-inputRange end time input
startLabelcatnip-input-date-start-labelVertical range+time From label
endLabelcatnip-input-date-end-labelVertical range+time To label
actionResetButtoncatnip-input-date-action-resetPanel Reset action button
actionCancelButtoncatnip-input-date-action-cancelPanel Cancel action button
actionSubmitButtoncatnip-input-date-action-submitPanel Apply action button
dismissButtoncatnip-input-date-dismissVisually hidden Close button
liveRegioncatnip-input-date-live-regionCalendar announcement region
supportingTextcatnip-input-date-supporting-textSupporting message

Catnip Design System by Signicat