Skip to content
Components, switch product

Date picker

<gui-date-picker> is a date field with a calendar popup. The user types the date part by part, as in a Date input, or picks it from a Calendar that opens under the field. Its value is an ISO date, such as 2026-10-05. For a start and an end date, use the Date range picker.

Code of the example above
DatePickerBasic.tsx
import { GuiDatePicker } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function DatePickerBasic() {
return <GuiDatePicker label="Check-in" />;
}

The element’s entry point is @golemui/gui-components/date-picker, which registers <gui-date-picker> and the <gui-date> and <gui-calendar> it is made of. To install the package and load the stylesheet, see Installation.

The @golemui/gui-components/react components have typed props and an on* prop for each event. React 18 or later.

CheckInField.tsx
import { useState } from 'react';
import { GuiDatePicker } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function CheckInField() {
const [checkIn, setCheckIn] = useState('');
return (
<GuiDatePicker
label="Check-in"
name="checkIn"
value={checkIn}
onGuiChange={(event) => setCheckIn(event.detail.value ?? '')}
/>
);
}

Properties

Property Type Default Description
icon string '' Icon class name shown inside the control, for example from an icon font.
toggleAriaLabel attribute toggle-aria-label string – Accessible name of the button that opens the popup. An empty value keeps the default.
dayAriaLabel attribute day-aria-label string – Accessible name of the day part. An empty value keeps the default.
monthAriaLabel attribute month-aria-label string – Accessible name of the month part. An empty value keeps the default.
yearAriaLabel attribute year-aria-label string – Accessible name of the year part. An empty value keeps the default.
showErrors attribute show-errors boolean true Whether the element renders its own error list. Elements that embed it turn it off and show the errors themselves.
localeId attribute locale-id string – BCP 47 locale for formatting and parsing, such as en-US or es.
value string – The date, as an ISO date (YYYY-MM-DD).
prevMonthIcon attribute prev-month-icon string '' Icon class name of the previous-month button.
nextMonthIcon attribute next-month-icon string '' Icon class name of the next-month button.
prevMonthAriaLabel attribute prev-month-aria-label string – Accessible name of the previous-month button. An empty value keeps the default.
nextMonthAriaLabel attribute next-month-aria-label string – Accessible name of the next-month button. An empty value keeps the default.
selectYearAriaLabel attribute select-year-aria-label string – Accessible name of the button that opens the year grid. An empty value keeps the default.
yearGridAriaLabel attribute year-grid-aria-label string – Accessible name of the year grid. An empty value keeps the default.
dayFormat attribute day-format 'numeric' | '2-digit' – How day numbers are written.
weekdayFormat attribute weekday-format 'short' | 'long' | 'narrow' – How weekday names are written in the header.
monthFormat attribute month-format 'numeric' | '2-digit' | 'long' | 'short' | 'narrow' – How the month is written in the header.
minDate attribute min-date string – Earliest selectable date, as an ISO date (YYYY-MM-DD).
maxDate attribute max-date string – Latest selectable date, as an ISO date (YYYY-MM-DD).
disabledRanges attribute disabled-ranges DateRange[] – Dates that cannot be picked, as { start, end } ISO date ranges.
numberOfMonths attribute number-of-months number – Number of months shown side by side.
invalidDateMessage attribute invalid-date-message string – Error for a complete but impossible date, such as February 31.
minDateMessage attribute min-date-message string – Error for a date before minDate.
maxDateMessage attribute max-date-message string – Error for a date after maxDate.
disabledDateRangeMessage attribute disabled-date-range-message string – Error for a date inside disabledRanges.
incompleteMessage attribute incomplete-message string – Error when focus leaves a partly filled value.
uid string – The id of the element's control. The ids of its label, hint and errors derive from it. Optional: when it is not set, the element generates one from its tag name and a page-wide counter, e.g. gui-textinput-3. Generated ids depend on creation order, so a server-rendered element must set uid or its ids will not match after hydration.

Form control properties

Every field has these, from the base class of the form controls.

Property Type Default Description
name string – The name the value is submitted under. Without it the element stays out of its form. Reflected, like a native control's: the form reads a single value's name from the attribute.
label string – The visible label, which also names the control for assistive technology. Without one the control has no accessible name; the date, time, range, tags and file fields warn about it in development builds.
hint string – Help text shown under the label and announced as the control's description.
errors string[] [] Error messages to show, typically from your own validation. They show as soon as they are set, unless touched is false.
touched boolean – Whether the user has interacted with the control. Leave it unset unless you validate on interaction: false holds errors back until it becomes true.
required boolean false The control needs a value: it is marked as required and, with a name, blocks submission.
readOnly attribute readonly boolean – The value can be read and focused but not changed.
disabled boolean – Disabled by its own attribute or by a disabled <fieldset> around it. Setting the property sets the attribute, like a native control's.
form read-only, no attribute HTMLFormElement | null – The <form> the element belongs to, if any.
validity read-only, no attribute ValidityState – The element's validity, like a native control's.
validationMessage read-only, no attribute string – The message the browser shows for an invalid value.

Methods

Method Description
checkValidity(): boolean –
reportValidity(): boolean –

Events

Every event bubbles and is composed, so you can listen on any ancestor.

Event Description
gui-input The user changed the value. detail.value is the new value.
gui-change The user committed the value. detail.value is the committed value.
gui-blur Focus left the control.
gui-input-error The element rejected what the user entered, such as an impossible date or a value out of bounds. detail.message is the error; show it through errors.

CSS custom properties

Property Default Description
--gui-calendar-width – Width of one month.
--gui-calendar-day-button-size – Size of each day.
--gui-calendar-change-month-button-width – Width of the previous- and next-month buttons.
--gui-calendar-change-month-button-height – Height of the previous- and next-month buttons.
--gui-calendar-year-button-width – Width of each year in the year grid.
--gui-calendar-year-button-height – Height of each year in the year grid.
--gui-calendar-year-grid-height – Height of the year grid.

value takes an ISO date (YYYY-MM-DD). The calendar opens when a part of the field gets focus, or from the button at the end of the field, on the month of the value or on the current month. It closes when the user picks a day, presses Escape, clicks outside or moves focus out of the element; picking a day and Escape return focus to the field.

A picked day, or a date typed in full, fires gui-input and then gui-change, with the ISO date in event.detail.value.

Value: 2026-11-30

Code of the example above
DatePickerValue.tsx
import { useState } from 'react';
import { GuiDatePicker } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function DatePickerValue() {
const [value, setValue] = useState<string | undefined>('2026-11-30');
return (
<>
<GuiDatePicker
id="date-picker-delivery"
label="Delivery date"
value={value}
onGuiChange={(event) => setValue(event.detail.value)}
/>
<p role="status">Value: {value}</p>
</>
);
}

locale-id takes a BCP 47 locale, such as en-US or es-ES. It sets the order of the parts of the field, the names of the months and weekdays and the first day of the week. Without it, the picker uses English (en). Set locale-id for another language. The value is the same ISO date in every locale.

Code of the example above
DatePickerLocale.tsx
import { GuiDatePicker } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function DatePickerLocale() {
return (
<div className="gui-grid gui-grid--row">
<div className="gui-grid__cell">
<GuiDatePicker label="Check-in" localeId="en-US" value="2026-12-14" />
</div>
<div className="gui-grid__cell">
<GuiDatePicker label="Llegada" localeId="es-ES" value="2026-12-14" />
</div>
</div>
);
}

weekday-format, month-format and day-format change how the calendar writes the weekdays, the month and the day numbers. See Calendar for an example.

min-date and max-date take ISO dates and are inclusive. disabled-ranges takes a JSON list of { "start", "end" } ISO dates, inclusive too; leave end out to disable one day. The calendar can’t pick those days, and its month buttons stop at the bounds.

The user can still type a date the calendar doesn’t offer. The element keeps it, marks it as invalid for its form and fires gui-input-error with the reason. Show the message with errors, as below. Change the day to 25 to see it. An impossible date, such as February 31, fires gui-input-error too, and doesn’t change the value.

Code of the example above
DatePickerBounds.tsx
import { useState } from 'react';
import { GuiDatePicker } from '@golemui/gui-components/react';
import type { DateRange } from '@golemui/gui-components';
import '@golemui/gui-components/index.css';
const closed: DateRange[] = [
{ start: '2026-12-24', end: '2026-12-26' },
{ start: '2026-12-31' },
];
export function DatePickerBounds() {
const [value, setValue] = useState<string | undefined>('2026-12-14');
const [errors, setErrors] = useState<string[]>([]);
return (
<GuiDatePicker
id="date-picker-stay"
label="Check-in"
hint="Open from December to February. Closed over Christmas and on New Year's Eve."
value={value}
minDate="2026-12-01"
maxDate="2027-02-28"
disabledRanges={closed}
errors={errors}
// The element reports what it rejects; show it with errors.
onGuiInputError={(event) => setErrors([event.detail.message])}
onGuiInput={(event) => {
setValue(event.detail.value);
setErrors([]);
}}
/>
);
}

Replace the English messages with min-date-message, max-date-message, disabled-date-range-message, invalid-date-message and incomplete-message, or translate them for every element as in i18n.

number-of-months shows that many months side by side. The month buttons move one month at a time.

Code of the example above
DatePickerMonths.tsx
import { GuiDatePicker } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function DatePickerMonths() {
return (
<GuiDatePicker label="Departure" numberOfMonths={2} value="2026-12-14" />
);
}

A disabled picker can’t be focused, changed or opened, and a form doesn’t submit it. A readonly picker opens its calendar but doesn’t change, and a form submits its value. icon shows an icon at the start of the field, as on the Date input.

Code of the example above
DatePickerDisabledReadonly.tsx
import { GuiDatePicker } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function DatePickerDisabledReadonly() {
return (
<div className="gui-grid gui-grid--row">
<div className="gui-grid__cell">
<GuiDatePicker label="Ordered on" value="2026-09-21" disabled />
</div>
<div className="gui-grid__cell">
<GuiDatePicker label="Shipped on" value="2026-09-23" readOnly />
</div>
</div>
);
}

With a name, <gui-date-picker> submits its ISO date under that name, such as checkIn=2026-12-14, and nothing while it is empty. required, a date outside min-date and max-date and a date in disabled-ranges block a submit. An impossible date, such as February 31, doesn’t change the value, so it doesn’t block a submit by itself. Clear the field and submit, then type a date in March.

Code of the example above
DatePickerNativeForm.tsx
import { useState } from 'react';
import { GuiButton, GuiDatePicker } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function DatePickerNativeForm() {
const [checkIn, setCheckIn] = useState<string | undefined>('2026-12-14');
const [result, setResult] = useState('');
return (
<form
id="date-picker-form"
onSubmit={(event) => {
event.preventDefault();
const data = Object.fromEntries(new FormData(event.currentTarget));
setResult(`Submitted ${JSON.stringify(data)}`);
}}
>
<div className="gui-grid gui-grid--row">
<div className="gui-grid__cell gui-grid__cell--span-3">
<GuiDatePicker
label="Check-in"
name="checkIn"
minDate="2026-12-01"
maxDate="2027-02-28"
value={checkIn}
onGuiChange={(event) => setCheckIn(event.detail.value)}
required
/>
</div>
<div className="gui-grid__cell">
<GuiButton type="submit" label="Book" />
</div>
</div>
<p role="status">{result}</p>
</form>
);
}

How the elements submit, validate and reset is in Native forms.

<gui-date-picker> renders into the light DOM, so you can style every part with plain CSS. It is a <gui-date>, a toggle button and a panel with a <gui-calendar>, which is there only while it is open. Here it is open, with en-US parts:

gui-date-picker
<gui-date-picker>
<span class="gui-label" id="checkin_label">
<span class="gui-label__text">Check-in</span>
</span>
<div class="gui-widget">
<gui-date id="checkin_date" class="gui-field">
<div class="gui-widget">
<div
role="group"
id="checkin"
class="gui-widget-input gui-parts gui-parts-ring gui-date-input"
aria-labelledby="checkin_label"
>
<!-- The month, day and year parts, as in gui-date -->
</div>
</div>
</gui-date>
<button
type="button"
class="gui-date-picker__arrow"
aria-haspopup="dialog"
aria-label="Show calendar"
aria-expanded="true"
aria-controls="checkin_popup"
>
<span class="gui-caret" aria-hidden="true"></span>
</button>
<div class="gui-picker__panel">
<gui-calendar
role="dialog"
id="checkin_popup"
aria-labelledby="checkin_label"
class="gui-field"
>
<!-- The month buttons, header and days grid, as in gui-calendar -->
</gui-calendar>
</div>
</div>
<div class="gui-validator" id="checkin_errors" role="alert"></div>
</gui-date-picker>
ClassPart
gui-labelThe label, with the text and the hint.
gui-label__textThe label text and the required marker.
gui-widget-hintThe hint.
gui-widgetThe box around the field, the button and the panel.
gui-date-picker__arrowThe button that opens and closes the calendar. Its caret turns while the calendar is open.
gui-caretThe caret in the button. See Carets.
gui-picker__panelThe floating panel around the calendar.
gui-validatorThe errors container under the field. The alert role announces new errors.
gui-validator--panelA copy of the errors at the bottom of the open panel, hidden from screen readers.
gui-validator__errorOne error message.

The field’s classes are on the Date input page and the calendar’s on the Calendar page.

The field reads the tokens of the Date input, and the calendar those of the Calendar. The picker adds its panel:

TokenWhat it styles
--gui-bg-defaultThe panel’s background.
--gui-border-defaultThe panel’s border.
--gui-radius-mdThe panel’s corner radius.
--gui-shadow-mdThe panel’s shadow.
--gui-space-2The panel’s padding.
--gui-space-3The space between the button and the edge.
--gui-intent-errorThe panel’s border while there are errors.
styles.css
/* Bigger days in every date picker. */
gui-date-picker {
--gui-calendar-day-button-size: 44px;
}

To restyle beyond the tokens, see Overriding styles; for dark mode and the Clay theme, see Themes and dark mode.

  • Name. The label names the field’s group and the calendar popup. Without a label the popup is named Calendar.
  • Toggle. The button at the end is named Show calendar, has aria-haspopup="dialog", reports aria-expanded and points at the popup with aria-controls. Rename it with toggle-aria-label, or translate it for every element under the key showCalendar.
  • Popup. The calendar has the dialog role. Its month buttons, year button, year grid and days are named as on the Calendar; the picker takes the same *-aria-label props and passes them on.
  • Parts. The field’s parts are named Day, Month and Year, as on the Date input.
  • Errors. While errors show, the field has aria-invalid="true" and points at them with aria-errormessage.
KeyAction
TabMoves from the field to the button, then through the calendar while it is open, then out.
Enter / Space on the buttonOpens the calendar and focuses today or the selected day, or closes it.
EscapeCloses the calendar and returns focus to the field.
Enter / Space on a dayPicks the day, closes the calendar and returns focus to the field.
Arrow keys in the calendarMove between the days, as on the Calendar.
Page Up / Page Down in the calendarMove to the same day in the previous or next month (the last day of a shorter month), or the nearest day the user can pick. With Shift, the same day in the previous or next year.
Home / End in the calendarMove to the first or last day of the week the user can pick, within the month.
Keys in the fieldType and move between the parts, as on the Date input.

What every element shares, such as translating the browser messages, is in Accessibility.