On this page
Import
import { Calendar, DatePicker } from '@envsemble/envui';
Usage
A DatePicker is a field with its label, description and error, whose button opens the calendar.
- Its value is a day as
YYYY-MM-DD, ornullfor none. - Leave it uncontrolled, with
defaultValue, or control it withvalueandonValueChange, which receivesnullonce the field is cleared. clearableadds a clear button to the field and the calendar.
import { useState } from 'react';
import { DatePicker } from '@envsemble/envui';
export default function PublishDate() {
const [publishOn, setPublishOn] = useState<string | null>('2026-10-20');
return (
<div style={{ inlineSize: 'min(100%, 20rem)' }}>
<DatePicker label="Publish on" value={publishOn} onValueChange={setPublishOn} clearable />
</div>
);
}A date and a time
granularity is day, the default, or minute, for a local date and time as YYYY-MM-DDTHH:mm.
- The time is chosen on wheels of hours, minutes every
minuteStepminutes, 15 by default, and, on a 12-hour clock, day periods. placeholderTime, asHH:mm, is the time a newly chosen day starts with, 00:00 by default.hourCyclesets the time's clock whatever the locale's:h23for 18:00 with no AM/PM wheel,h12for 6:00 PM. The value stays on the 24-hour clock.
<DatePicker
label="Meeting"
granularity="minute"
placeholderTime="09:00"
minuteStep={30}
hourCycle="h23"
value={meeting}
onValueChange={setMeeting}
clearable
/>
Range and format
min and max, in the value's format, make earlier and later days unavailable, and the month buttons stop at them. Check the order of two dates yourself, and set error.
locale, EnvUIProvider's by default, sets the shown value and the calendar's names.weekStartsets the first day of the week, from 0 for Sunday.formatOptionssets theIntl.DateTimeFormatoptions of the shown value.
In a form
name submits the value as YYYY-MM-DD, or YYYY-MM-DDTHH:mm, a local date without a zone; converting it to a moment belongs to the application.
requiredkeeps an empty field from submitting, and a reset restoresdefaultValue.- Use
readOnly, notdisabled, for a date people can't change. - Values are
YYYY-MM-DD, so two dates compare as text: on submit, set the last field'serrorwherelast < first.
<form onSubmit={request}>
<DatePicker label="First day" name="first" defaultValue="2026-11-02" required />
<DatePicker label="Last day" name="last" defaultValue="2026-11-06" required error={error} />
<Button type="submit">Request leave</Button>
</form>
Sizes
sizeissm,mdorlg; without it, the field takes its container's control height.- With
visibleLabel={false},placeholdershows in place of the label; name the field witharia-label. - The field is 12 rem wide at least, also in a container sized to its content, and in a narrower container it takes the container's width.
<DatePicker
size="sm"
visibleLabel={false}
aria-label="Due"
placeholder="Due"
granularity="minute"
/>
Calendar
Calendar is the month on its own, for a page or a panel: it takes value, defaultValue and onValueChange, min, max, weekStart and locale, as the field does.
<Calendar aria-label="Planning" value={day} onValueChange={setDay} />
Composition
open, defaultOpen and onOpenChange control the calendar; onOpenChange also receives why it opens or closes, PickerOpenChangeDetails, such as item-press for a chosen day. clearLabel, todayLabel, nowLabel, timeLabel, previousMonthLabel and nextMonthLabel name its buttons, from EnvUIProvider's messages by default. className and style reach the field's root, and ref the button.
The field's parts are the root, env-field with env-date-picker; the control, env-date-picker-control, with the label, env-date-picker-label, the value, env-date-picker-value, the clear button, env-date-picker-clear, and the calendar icon, env-date-picker-icon; then the description, env-field-description, and the error, env-field-error. The popup is the picker card TimePicker and MonthPicker open too, env-picker-popup with env-date-picker-popup. Its body, env-picker-popup-body, holds the calendar, with env-calendar-previous, env-calendar-title, env-calendar-next and env-calendar-day, and the times, env-date-picker-time, beside it with granularity="minute"; its footer, env-picker-popup-footer with env-date-picker-actions, holds the actions, Clear in env-picker-popup-footer-end with env-date-picker-actions-end.
Customize
Its popup is frosted, as every popup is: --env-popup-opacity, --env-popup-blur and --env-popup-shadow, set on a theme, change it, as Popover describes.
Accessibility
You provide
- A
label, oraria-labelon a field without one. - Validation, such as the order of two dates, and its
error. - The labels in the application's language.
envUI provides
- The field as a
comboboxbutton named by its label, with its description and error. - The calendar as a grid of days, each named by its full date, with one tab stop.
- Time wheels as
spinbuttons named Hours, Minutes and AM/PM. - The month heading as a live region, announced as it changes.
Props
DatePicker
A field for a date, or a date and time, that shows the value in the reader's locale and opens a calendar to choose it, with keyboard access following the WAI-ARIA date picker.
| Prop | Type | Description |
|---|---|---|
ref | Ref< | The field's button, which shows the value and opens the calendar. |
className | string | The field's class, on its root element, beside env-field and env-date-picker. |
style | CSSProperties | Styles of the field's root element. |
value | stringnull | The value: a day as YYYY-MM-DD, or with the minute granularity a local date and time as YYYY-MM-DDTHH:mm. null, or an empty string, for none. |
defaultValueDefault null | stringnull | The value an uncontrolled field starts with, and that a form reset restores; none by default. |
onValueChange | ( | Receives the new value, or null once the field is cleared. |
granularityDefault 'day' | 'day''minute' | What the value holds: day, a date as YYYY-MM-DD, or minute, a date and a time as YYYY-MM-DDTHH:mm, chosen in a list of times beside the calendar. |
min | string | The earliest value, as YYYY-MM-DD or YYYY-MM-DDTHH:mm; earlier days are unavailable. |
max | string | The latest value, as YYYY-MM-DD or YYYY-MM-DDTHH:mm; later days are unavailable. |
placeholderTime | string | The time a newly chosen day starts with, as HH:mm; 00:00 by default. |
minuteStepDefault 15 | number | With the minute granularity, the minutes between the times the list offers, from 1 to 60. A value between them still shows in the list, in its place. |
locale | string | The locale of the shown value and the calendar's names and numbers: EnvUIProvider's, else the browser's. Dates are Gregorian, also in a locale with a calendar of its own. |
hourCycleDefault the locale's | 'h12''h23' | With the minute granularity, the clock of the shown time and the wheels, whatever the locale's: h23 for 18:00, with no AM/PM wheel, or h12 for 6:00 PM. The value stays on the 24-hour clock. |
weekStartDefault the locale's, or Monday where the browser cannot tell | 0123456 | The calendar's first day of the week, from 0 for Sunday to 6 for Saturday. |
formatOptions | Intl. | How the field shows the value: Intl.DateTimeFormat options, by default the medium date style and, with the minute granularity, the short time style, in the Gregorian calendar unless they name another. |
name | string | The name the value is submitted under with a form, as YYYY-MM-DD or YYYY-MM-DDTHH:mm. |
requiredDefault false | boolean | A value is needed: an empty field keeps its form from submitting and takes focus. |
readOnlyDefault false | boolean | The value can be read and focused but not changed. |
placeholder | string | Shown while the field is empty and its label floats or is hidden. |
clearableDefault false | boolean | A clear button in the field and in the calendar removes the value. |
open | boolean | Whether the calendar is open; with `onOpenChange` it controls it. |
defaultOpenDefault false | boolean | Whether an uncontrolled calendar starts open; closed by default. |
onOpenChange | ( | Called with the new state, and why, when the calendar opens or closes. |
clearLabelDefault 'Clear', or EnvUIProvider's messages.datePicker.clear | string | Accessible name of the field's clear button and text of the calendar's. |
todayLabelDefault 'Today', or EnvUIProvider's messages.datePicker.today | string | The calendar's shortcut to today. |
nowLabelDefault 'Now', or EnvUIProvider's messages.datePicker.now | string | With the minute granularity, the calendar's shortcut to the current date and time. |
timeLabelDefault 'Time', or EnvUIProvider's messages.datePicker.time | string | With the minute granularity, the heading and accessible name of the list of times. |
previousMonthLabelDefault 'Previous month', or EnvUIProvider's messages.calendar.previousMonth | string | Accessible name of the calendar's previous month button. |
nextMonthLabelDefault 'Next month', or EnvUIProvider's messages.calendar.nextMonth | string | Accessible name of the calendar's next month button. |
label | ReactNode | The field's visible name, such as Project name; it also names the control for assistive technology. |
description | ReactNode | Lasting guidance under the field, such as a format or a limit, linked to the control as its description. |
error | ReactNode | A message under the field that says how to correct the value. While it is set, the control is invalid (aria-invalid) and the message joins its description, after the description. |
size | 'sm''md''lg' | The control height, sm, md or lg; without it, the container's, and else md. sm is for a field with its label hidden. |
visibleLabelDefault true | boolean | The label shows in the field, where it rests while the field is empty and floats into the outline while the field is in use or has a value. false hides it, for a field whose purpose is clear without it, such as a search in a toolbar: the label still names the field for assistive technology, and a placeholder gives the visible guidance. |
Also accepts the native props of <button>, such as ref, className and aria-* attributes.
Calendar
A month of days to choose one from, following the WAI-ARIA date picker grid: the arrow keys move by day and week, Page Up and Page Down by month (with Shift, by year), Home and End to the week's ends, and Enter or Space chooses the day. Named with aria-label or aria-labelledby, it is a group around the month's grid.
| Prop | Type | Description |
|---|---|---|
value | stringnull | The chosen day as YYYY-MM-DD, or null for none. |
defaultValueDefault null | stringnull | The day an uncontrolled calendar starts with; none by default, which shows today's month. |
onValueChange | ( | Receives the chosen day as YYYY-MM-DD. |
min | string | The earliest day that can be chosen, as YYYY-MM-DD; earlier days are unavailable. |
max | string | The latest day that can be chosen, as YYYY-MM-DD; later days are unavailable. |
weekStartDefault the locale's, or Monday where the browser cannot tell | 0123456 | The first day of each week, from 0 for Sunday to 6 for Saturday. |
locale | string | The locale of the month and weekday names and the day numbers: EnvUIProvider's, else the browser's. The days are always Gregorian, also in a locale with a calendar of its own. |
previousMonthLabelDefault 'Previous month', or EnvUIProvider's messages.calendar.previousMonth | string | Accessible name of the previous month button. |
nextMonthLabelDefault 'Next month', or EnvUIProvider's messages.calendar.nextMonth | string | Accessible name of the next month button. |
Also accepts the native props of <div>, such as ref, className and aria-* attributes.
Part names
Each part's class and state attributes are public and versioned, for an application's CSS to style.
DatePicker
env-date-picker- The date field.
env-date-picker-actions- The row of actions under the calendar, the picker card's footer.
env-date-picker-actions-end- The actions at the end of that row.
env-date-picker-clear- The button that clears the date.
env-date-picker-control- The field's well.
env-date-picker-end- The buttons at the end of the well.
env-date-picker-icon- The calendar icon.
env-date-picker-label- The label.
env-date-picker-native- The native input that holds the value for forms.
env-date-picker-panes- The calendar and the times side by side.
env-date-picker-placeholder- The text shown without a date.
env-date-picker-popup- The picker card with the calendar, also on TimePicker and MonthPicker.
env-date-picker-time- The times beside the calendar.
env-date-picker-time-title- The title over the times.
env-date-picker-trigger- The button that opens the calendar.
env-date-picker-value- The chosen date as text.
data-action-count1·2on env-date-picker-controldata-label-floating- Present on env-date-picker-control
data-label-hidden- Any value, or present
data-popup-open- Present on env-date-picker-control
Calendar
env-calendar- The calendar of one month.
env-calendar-day- One day.
env-calendar-day-mark- The mark under a day, such as today's.
env-calendar-grid- The grid of days.
env-calendar-header- The row with the month and the previous and next buttons.
env-calendar-next- The button for the next month.
env-calendar-pad- An empty cell before the first day or after the last.
env-calendar-previous- The button for the previous month.
env-calendar-title- The month and year.
data-date- Any value, or present on env-calendar-day
Strings
EnvUIProvider's messages overrides each, and a component's own label prop wins over it.
messages.calendar.previousMonth"Previous month"The previous-month button's name.messages.calendar.nextMonth"Next month"The next-month button's name.messages.datePicker.clear"Clear"The clear button's name.messages.datePicker.today"Today"Picks today.messages.datePicker.now"Now"Picks the current time.messages.datePicker.time"Time"Names the time field.messages.timePicker.clear"Clear"The clear button's name.messages.timePicker.now"Now"Picks the current time.messages.timePicker.hours"Hours"Names the column of hours.messages.timePicker.minutes"Minutes"Names the column of minutes.messages.timePicker.dayPeriod"AM/PM"Names the column of the day's halves, on a 12-hour clock.
Changelog
- 1.0.0
showLabelisvisibleLabel, named after the label thatvisibleLabel={false}hides.The field keeps its minimum width, 12 rem, in a container sized to its content, such as an inline-flex toolbar, rather than growing after the container measured it and pushing its neighbours onto another row; in a narrower container it still takes the container's width. The calendar's month and year,
env-calendar-heading, areenv-calendar-title.With the minute granularity, the time is chosen on wheels of hours, minutes every
minuteStepminutes (15) and, on a 12-hour clock, day periods, beside the calendar, in place of the time field under it; turning a wheel sets the time at once. The calendar has no Done button, anddoneLabelis gone: it closes as a date-only one does. The field and popup are shared with TimePicker and MonthPicker.withTimeisgranularity,"day"or"minute";hintisdescription;variant="outlined"isvariant="outline".classNameandstylestyle the field's root rather than the button, which takesref. The calendar opens on the shared popup, its month buttons are ghost icon buttons, and its labels come from EnvUIProvider'smessages, as its locale does:env-date-time-wellisenv-date-picker-control.DateTimeFieldisDatePicker, with theenv-date-picker-*classes; the page isdate-picker.- 1.0.0-prerelease.6
Colors under the pointer and while pressed change with
--env-motion-ease-enter, rather than easing in slowly, so hover and press show from the first frame.The calendar's popup opens over
--env-motion-duration-medium, fading in and growing from 98 % with--env-motion-ease-enter, rather than growing from 96 % over the slow duration, so it shows from its first frames rather than late.The field keeps its focused frame and label until the calendar has closed, rather than fading and coming back as focus returns.
With the minute granularity,
hourCycle,h12orh23, sets the time's clock whatever the locale's, such as 18:00 with no AM/PM wheel in English; the value staysYYYY-MM-DDTHH:mm.The calendar's days, on their own and in the popup, are a little less than a row height wide, 24 px at the compact scale and 32 px at the comfortable one, so the columns stand close around the numbers; they still touch, and touch screens keep touch-sized days.
A clearable field's clear button and its calendar icon stand a step apart, so they don't crowd each other in a small field.
While its calendar is open, the field keeps its focused frame, the accent edge and label, also when focus is in the popup, as when it opens under the pointer.
The calendar names the weekdays by their first two letters at every width and scale, Mo Tu We in English, where those tell the seven apart, so the names never run into each other in the popup's narrow days.
The calendar's month buttons show larger arrows, 1.25 rem, on slightly smaller buttons, so the month's name stays on one line, and the header keeps a little room under it before the weekdays, so it reads at the compact scale too.
The chosen hour and minute take the chosen day's solid accent fill rather than the selection's tint, and are round and as tall as a day, as the chosen day is, so a chosen day and time look alike and the wheels stay narrow; a wheel with fewer values than it shows rows, such as minutes every 15, no longer loops and shows a value twice, while its arrow keys still wrap around.
As a time wheel turns to a row pressed or scrolled to, the fill stays on that row rather than passing over the rows on the way, and a row's text takes the fill's color only while it is on the fill, so a value it leaves is never white on the popup.
With a time, the wheels move under the calendar where the card has no room for them beside it, rather than running past its edge.
Days outside
minandmaxtake the disabled text color, faded, so they can't be taken for days that can be chosen; today keeps its accent color.The
floatingvariant and thevariantprop are gone: the field is outlined, and takessize="lg"in a long form on a page. The field takes a text area's rounded corners rather than round ends. A small one with a visible label takes the medium height, so its floated label and its value each have room, and says so in the console while developing:smis for a field with its label hidden.The calendar card takes the width of a field a little wider than it, up to 1 rem, and in a narrow window it is at least as wide as its field, so it ends with the field; Today and Clear follow the calendar's six weeks closely. Beside the calendar, the Time heading shares the line of the month's name.
- 1.0.0-prerelease.5
defaultTimeisplaceholderTime, as React Aria names it:defaultnames an uncontrolled starting value elsewhere.The calendar popup is frosted: the popup's color lets a little of what is behind through, blurred, with a soft shadow and no outline edge but a faint hairline in dark, and is solid with its edge at high contrast and with reduced transparency. Its inset is a panel's, as wide as a popup row's corner: 14 px, 11.2 px at the compact scale. The calendar leads with the month's name, its buttons side by side at the end; the days of a week touch, a row height wide; today is in the accent color rather than ringed, and a day under the pointer takes the neutral fill.