Skip to main content

DateInputRange

Capture date range input from user.

github
View source code

Migration Information

For teams migrating from the V1 to V2 component, please refer to the migration guide for changes to the component.
Component Guide
import { DateInputRange } from '@uhg-abyss/web/ui/DateInputRange';
() => {
const [values, setValues] = useState<DateRange>({
from: dayjs().format('MM/DD/YYYY'),
to: dayjs().add(5, 'day').format('MM/DD/YYYY'),
});
return (
<DateInputRange
label="DateInputRange Sandbox"
values={values}
onChange={setValues}
/>
);
};

Day.js​

DateInputRange relies on the Day.js library to handle date operations. Several inputs to the DateInputRange are Dayjs objects.

Abyss includes a Day.js tool, which includes a number of preset Day.js plugins, but you can also install Day.js separatelyopens in a new window.

import { dayjs } from '@uhg-abyss/web/tools/dayjs';

Variants​

Inputs with calendar​

The default variant for DateInputRange shows two input fields, each with a button to open a calendar.

Inputs only​

Use the inputOnly prop when the dates can be easily entered without a calendar.

Using useForm and FormProvider simplifies form management by providing out-of-the-box validation, form state handling, and performance optimizations, leveraging the power of react-hook-form.

useState​

Using the useState hook gets values from the component state.

Display properties​

Label​

Use the label prop to display a label above the inputs. To hide the label, set hideLabel to true.

Use isRequired and isOptional for further customization.

useState only

If using useForm, do not use isRequired. The same functionality can be achieved with required: true in validators.

Helper​

Use the helper prop to display a help icon next to the label. Simply passing a string value will render the default helper, a Tooltip containing that string. The helper can be customized by passing in a node. It is recommended to use either a Tooltip or a Popover. See When should I use a Tooltip vs. a Popover? for more information on best practices regarding the two.

Subtext​

Use the subText prop to display helpful information related to the input fields.

Date format​

Use the dateFormat prop to specify the format of the date displayed in the input fields. The value given will also change the fields' formatting hints and input masks. The default format is 'MM/DD/YYYY'.

Important

The format must be compatible with the Day.js libraryopens in a new window. Due to the input mask used, DateInput does not support any substrings that would require non-numeric characters.

Of the available formatting substrings, only the following are supported:

FormatDescription
'YY'Two-digit year
'YYYY'Four-digit year
'M'The month, beginning at 1
'MM'The month, 2-digits
'D'The day of the month
'DD'The day of the month, 2-digits
'd'The day of the week, with Sunday as 0

Important

The initial/default value(s), provided either through useForm or useState, must also be in the specified date format.

Hide placeholders​

By default, the inputs will contain a formatting placeholder that matches the specified date format. Use the hidePlaceholders prop to control the placeholders' visibility. The default value is false.

Note

The formatting masks are unaffected by this prop. The placeholders are only visible if there is no text in the input.

Width​

Use the width prop to set the width of the input fields.

Match anchor width​

By default, the calendar will match the width of the input fields. To disable this behavior, set the matchAnchorWidth prop to false. The calendar will then take up the minimum width required.

Note

If the input field width is less than the minimum width of the calendar (340px), the value of matchAnchorWidth will be ignored to prevent the calendar from overflowing the container.

Validation​

Validators (useForm)​

Form Compatibility
useState
useForm

Use the validators prop to set validation rules for the field when using useForm. See the examples below for implementation on various types of validation.

Tip

The default error message when required is true is minimally acceptable for accessibility. It is highly recommended to customize it to be more specific to the use of the field and form.

Error message (useState)​

Form Compatibility
useState
useForm

Use the errorMessage prop to display a custom error message below the input fields when using useState.

Success message​

Form Compatibility
useState
useForm

Use the successMessage prop to display a custom success message below the input field. To provide a single success message across all form input components using useForm/FormProvider, you can provide successMessage to FormProvider as shown here.

Highlighted​

Form Compatibility
useState
useForm

Use the highlighted prop to enable a distinct background color when fields are required. To supply this across all form input components using useForm/FormProvider, you can provide highlighted to FormProvider as shown here.

Minimum and maximum dates​

Use the minDate and maxDate props to only allow dates within a given range to be selected in the calendar. Both props accept a Dayjs object. These values are inclusive endpoints, meaning that the date(s) provided can be selected. Learn more about these values in the Calendar documentation.

In the example below, only the dates from one month before today's date to one month after can be selected.

Warning

The input fields will still allow users to enter dates outside of the defined minDate and maxDate values, so manual validation is required.

Exclude dates​

Use the excludeDate prop to prevent certain dates from being selected in the calendar. excludeDate accepts a predicate function and checks each date in the current month against it. If the function returns true, the matching date will be disabled.

In the example below, the excludeDate function disables all Sundays and Saturdays.

Warning

The excludeDate function does not prevent the excluded dates from being contained within a range, only from being selected as endpoints. Additionally, the input fields will still allow users to enter dates that are excluded, so manual validation is required.

Validation below menu​

Form Compatibility
useState
useForm

Set the validationBelowMenu prop to true to relocate the error and success message validation to below the menu, when open.

The default is false and the validation message will always remain displayed below the selection container, even when the calendar is open.

Interactivity​

Clearable​

Set the isClearable prop to true to display a clear button in the input fields. The optional onClear callback prop can be used to trigger additional actions when the clear button is clicked.

Disabled​

Set the isDisabled prop to true to disable the input fields, preventing user interaction. The inputs will still display the current values, but users cannot change them.

Enable outside scroll​

Set the enableOutsideScroll prop to true to allow the page to be scrolled while the calendar is open. The default value is false.

Confirm selection​

By default, selecting a date range in the calendar will set the range and close the calendar. By setting the confirmSelection prop to true, the calendar will display "Apply" and "Cancel" buttons and the user will have to press the "Apply" button to confirm the selection and close the calendar.

Use the onApply and onCancel props to add extra behavior to execute when the "Apply" and "Cancel" buttons are clicked, respectively. onApply will receive the selected dates as an object of the form:

{
from: dayjs.Dayjs;
to: dayjs.Dayjs;
}

Individual DateInput props​

The DateInput components that make up DateInputRange can be customized to a degree. The following props can be passed to either the fromFieldConfig or toFieldConfig object to customize the respective DateInput:

  • ref
  • label
  • hideLabel
  • subText
  • onFocus
  • onBlur
  • onPaste
  • successMessage
  • errorMessage
  • onClear
  • inputLeftElement
  • onPickerButtonClick

See the DateInput docs for more information on the usage of these props.

Note

When using DateInputRange with useForm, the overall component's validation is used as described in the Validation section above, but the individual DateInput components will still use the successMessage and errorMessage props to display messages below the respective input fields.

Responsiveness​

On screens 420px wide or smaller, the inputs will stack vertically and the calendar will be placed in a full-screen takeover instead of a popup. Resize the window to see the changes!

DateInputRange Props​

Name
Type
DefaultRequiredA11yDescription
className
string | undefined
CSS class name to apply to each element within the component
confirmSelection
boolean | undefined
false
If true, the Calendar will only close when the user presses the "Apply" button
css
CSSProperties | Partial<Record<"abyss-date-input-range-label" | "abyss-date-input-range-root" | "abyss-date-input-range-sub-text" | "abyss-date-input-range-format-text" | ... 14 more ... | "abyss-date-input-descriptors", CSSProperties>> | undefined
Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation
See CSS Prop Styling for more information
data-testid
string | undefined
Suffix used to create a unique ID used for automated testing
See Component Testing for more information
dateFormat
string | undefined
'MM/DD/YYYY'
A string representing the date format to be used in the input, exposed to screen readers via aria-describedby so users know the expected format; must be compatible with the Day.js library.
disableDefaultProviderProps
boolean | undefined
false
If set to true, the component will not use the DefaultPropsProvider values.

If you aren’t using the DefaultPropsProvider, this prop can be ignored.
enableOutsideScroll
boolean | undefined
false
If true, the page will remain scrollable when the popover is open
errorMessage
string | undefined
Error message to display for the input. Only used when not in a FormProvider.
errorMessage should not exist in useForm mode.
excludeDate
((date: Dayjs) => boolean) | undefined
Predicate function to exclude matching dates from the Calendar. This applies even to dates within the minDate and maxDate range, if applicable.
fromFieldConfig
DateInputRangeFieldProps | undefined
Props for the "From" date field
helper
string | number | bigint | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...> | null | undefined
Helper element next to label
hiddenFrom
Breakpoint | undefined
When defined, the component is hidden once the screen width reaches the specified breakpoint.
hideLabel
boolean | undefined
false
If true, hides the label visually while keeping it accessible to screen readers.
hidePlaceholders
boolean | undefined
false
If true, the placeholders in the inputs will be hidden
highlighted
boolean | undefined
false
If true, the input field will be highlighted
inputOnly
boolean | undefined
false
If true, only the input field will be rendered without the picker button and popover calendar
isClearable
boolean | undefined
If true, the input will display a clear button
isDisabled
boolean | undefined
false
If true, the input will be disabled
isOptional
boolean | undefined
false
If true, the label will be appended with "(Optional)"
isRequired
boolean | undefined
Whether the input is required. Only used when not in a FormProvider.
isRequired should not exist in useForm mode.
label
string
The label for the input; associated with it so screen readers announce it as the input's accessible name.
matchAnchorWidth
boolean | undefined
true
If true, the Calendar will match the width of the input
maxDate
Dayjs | undefined
If present, the Calendar will only display dates of this value's month and earlier
minDate
Dayjs | undefined
If present, the Calendar will only display dates of this value's month and later
model
string | undefined
model should not exist in useState mode.
Model name for form validation. Only used when in a FormProvider.
onApply
((selectedDates: { from?: Dayjs | undefined; to?: Dayjs | undefined; }) => void) | undefined
Callback executed when the "Apply" button is clicked. Only used when confirmSelection is true.
onBlur
FocusEventHandler<HTMLInputElement> | undefined
Callback function executed when the input is blurred
onCancel
(() => void) | undefined
Callback executed when the "Cancel" button is clicked. Only used when confirmSelection is true.
onChange
((values: DateRange) => void) | undefined
Callback function executed when the input value changes
onClear
(() => void) | undefined
Callback function executed when the input is cleared
onFocus
FocusEventHandler<HTMLInputElement> | undefined
Callback function executed when the input is focused
openPosition
"default" | "top" | "bottom" | undefined
'default'
Determines where the Calendar will open relative to the input
slotProps
Partial<Record<string, SlotPropsValue<string>>> | undefined
Props to pass to individual internal slots of the component, keyed by the slot name
(e.g. 'button-root'). Supports className, css, style, aria-*, data-*,
data-testid, and nested slotProps for child Abyss components.
See slotProps for more information
subText
string | undefined
Additional descriptive text for the input
successMessage
string | undefined
Success message to display for the input
toFieldConfig
DateInputRangeFieldProps | undefined
Props for the "To" date field
validationBelowMenu
boolean | undefined
false
If true, displays error and success validation messages below the menu
validators
DateInputRangeValidators | undefined
Enhanced validators that can return field-specific error messages
for date input range validation
values
DateRange | undefined
The values of the input. Only used when not in a FormProvider.
visibleFrom
Breakpoint | undefined
When defined, the component is hidden until the screen width reaches the specified breakpoint.

DateInputRange Classes​

Class NameDescription
.abyss-date-input-descriptorsThe descriptors for the individual date inputs.
.abyss-date-input-range-descriptorsThe descriptors container
.abyss-date-input-range-format-textThe takeover header format text
.abyss-date-input-range-from-fieldThe from date input field
.abyss-date-input-range-from-selection-display-textThe from date selection display text
.abyss-date-input-range-input-label-wrapperThe wrapper for the input label
.abyss-date-input-range-input-sub-textThe input sub text
.abyss-date-input-range-inputs-wrapperThe wrapper for the from and to inputs
.abyss-date-input-range-labelThe takeover header label
.abyss-date-input-range-label-wrapperThe wrapper for the takeover header label
.abyss-date-input-range-range-labelThe range label
.abyss-date-input-range-rootThe root container of the date input range
.abyss-date-input-range-selection-displaySelectionDisplay rendered for the from/to takeover fields
.abyss-date-input-range-sub-textThe takeover header sub text
.abyss-date-input-range-takeover-calendars-containerThe container for the calendars in the takeover
.abyss-date-input-range-takeover-selection-display-containerThe container for the selection display in the takeover
.abyss-date-input-range-to-fieldThe to date input field
.abyss-date-input-range-to-selection-display-textThe to date selection display text
.abyss-date-input-range-virtual-calendar-itemVirtualCalendarItem rendered per virtualized calendar month

DateInput Classes​

Class NameDescription
.abyss-date-input-calendarThe calendar
.abyss-date-input-inputThe date input element
.abyss-date-input-picker-inputPickerInput rendered by DateInput

Calendar Classes​

Class NameDescription
.abyss-calendar-arrow-buttonArrow button root element
.abyss-calendar-arrow-button-iconArrow button icon element
.abyss-calendar-day-grid-bodyCalendar table body
.abyss-calendar-day-grid-body-rowCalendar table body row
.abyss-calendar-day-grid-day-buttonDay cell button
.abyss-calendar-day-grid-day-cellDay cell root element
.abyss-calendar-day-grid-headerCalendar table header
.abyss-calendar-day-grid-header-cellCalendar table header cell
.abyss-calendar-day-grid-header-rowCalendar table header row
.abyss-calendar-day-grid-rootCalendar table root element
.abyss-calendar-footerCalendar footer
.abyss-calendar-footer-filled-buttonCalendar footer filled button
.abyss-calendar-footer-outline-buttonCalendar footer outline button
.abyss-calendar-header-month-buttonCalendar header month button
.abyss-calendar-header-month-year-containerCalendar header month/year container
.abyss-calendar-header-next-month-buttonCalendar header next month button
.abyss-calendar-header-next-year-buttonCalendar header next year button
.abyss-calendar-header-previous-month-buttonCalendar header previous month button
.abyss-calendar-header-previous-year-buttonCalendar header previous year button
.abyss-calendar-header-rootCalendar header root element
.abyss-calendar-header-year-buttonCalendar header year button
.abyss-calendar-month-year-list-containerMonth/year list container
.abyss-calendar-month-year-picker-back-buttonMonth/year picker back button
.abyss-calendar-month-year-picker-headerMonth/year picker header
.abyss-calendar-month-year-picker-header-textMonth/year picker header text
.abyss-calendar-month-year-picker-list-optionMonth/year picker list option
.abyss-calendar-rootCalendar root element

The example below includes date input range field that open a date picker that implements the dialog design pattern. The dialog contains a calendar that uses the grid pattern to present buttons that enable the user to choose a day from the calendar. Choosing a date from the calendar closes the dialog and populates the date input field. When the dialog is opened, if the input field is empty, or does not contain a valid date, then the current date is focused in the calendar. Otherwise, the focus is placed on the day in the calendar that matches the value of the date input field. Opening the calendar from either the start date or end date button prompts the user to select the first day and then the last day.

The start and end date inputs are wrapped in a <fieldset> that carries role="radiogroup" and aria-roledescription="Group". This allows aria-required and aria-invalid to be announced against the grouping as a whole rather than against an individual input, matching the approach used by RadioGroup and CheckboxGroup.

Adheres to the Date Picker Dialog WAI-ARIA design patternopens in a new window.

Keyboard Interactions​

KeyDescription
EscCloses the dialog and returns focus to the Choose Starting Date or Choose Ending Date button
TabMoves focus to next element in the dialog Tab sequence
Shift + TabMoves focus to previous element in the dialog Tab sequence

Keyboard Interactions​

KeyDescription
SpaceChange the month and/or year displayed in the calendar grid
EnterChange the month and/or year displayed in the calendar grid

Keyboard Interactions​

KeyDescription
SpaceSelect the date, close the dialog, and move focus to the Choose Starting Date or Choose Ending Date button
EnterSelect the date, close the dialog, and move focus to the Choose Starting Date or Choose Ending Date button
Up ArrowMoves focus to the same day of the previous week
Down ArrowMoves focus to the same day of the next week
Right ArrowMoves focus to the next day
Left ArrowMoves focus to the previous day
Page UpChanges the grid of dates to the previous month
Page DownChanges the grid of dates to the next month
Shift + Page DownChanges the grid of dates to the next Year
Shift + Page UpChanges the grid of dates to the previous Year

Known BrAT issues​

JAWS​

JAWS announces formatting hint characters (default: "__/__/____") in date inputs.

  • By default, JAWS announces the date format characters shown in the field
  • NVDA and VoiceOver ignore these characters and announce updates without them

NVDA​

  • May not announce all group level information in browse mode when receiving focus. This can happen when the first element to receive focus is a helper.
  • In focus mode, all group level settings should announce as expected. Focus mode is triggered when a date field receives focus, announcing the group fully when there are no helpers before it.

Component Tokens​

Tip

Click on the token row to copy the token to your clipboard.

DateInputRange Tokens​

Token NameValue
date-input-range.color.border.selection-indicator
#E5E5E6
date-input-range.color.text.selection-indicator
#4B4D4F
date-input-range.border-width.bottom.separator
1px
date-input-range.spacing.gap.horizontal.web.fields
16px
date-input-range.spacing.gap.vertical.container
16px
date-input-range.spacing.gap.vertical.mobile.fields
16px
date-input-range.spacing.gap.vertical.takeover-input-container
16px
date-input-range.spacing.padding.all.takeover-week-days
16px
date-input-range.spacing.padding.bottom.takeover-input-container
24px
date-input-range.spacing.padding.horizontal.takeover-input-container
16px
date-input-range.spacing.padding.top.takeover-calendar
16px
date-input-range.spacing.padding.top.takeover-input-container
16px

DateInput Tokens​

Token NameValue
date-input.color.border.selection-indicator
#E5E5E6
date-input.color.icon.default
#323334
date-input.color.icon.disabled
#7D7F81
date-input.color.icon.utility.active
#000000
date-input.color.icon.utility.hover
#323334
date-input.color.icon.utility.rest
#4B4D4F
date-input.color.surface.button.active
#E5E5E6
date-input.color.surface.button.hover
#F3F3F3
date-input.color.surface.button.rest
#FFFFFF
date-input.color.surface.picker-mobile
#FFFFFF
date-input.color.surface.selection-indicator.default
#F3F3F3
date-input.color.surface.selection-indicator.highlighted
#E5F8FB
date-input.color.text.sub-label
#4B4D4F
date-input.color.text.selection-indicator
#4B4D4F
date-input.border-radius.all.selection-indicator
4px
date-input.border-width.all.selection-indicator
1px
date-input.border-width.bottom.separator
1px
date-input.sizing.all.icon
20px
date-input.spacing.gap.horizontal.takeover-button-container
8px
date-input.spacing.gap.horizontal.selection-indicator
12px
date-input.spacing.gap.vertical.selection-indicator
8px
date-input.spacing.padding.all.takeover-button-container
16px
date-input.spacing.padding.all.takeover-header
16px
date-input.spacing.padding.bottom.takeover-input-container
24px
date-input.spacing.padding.horizontal.takeover-input-container
16px
date-input.spacing.padding.horizontal.selection-indicator
12px
date-input.spacing.padding.top.takeover-input-container
16px

Calendar Tokens​

Token NameValue
calendar.color.border.container
#CBCCCD
calendar.color.border.day-button.today
#002677
calendar.color.icon.utility.active
#00184D
calendar.color.icon.utility.disabled
#7D7F81
calendar.color.icon.utility.hover
#004BA0
calendar.color.icon.utility.rest
#002677
calendar.color.surface.container
#FFFFFF
calendar.color.surface.day-button.default.active
#E5E5E6
calendar.color.surface.day-button.default.hover
#F3F3F3
calendar.color.surface.day-button.default.rest
#FFFFFF
calendar.color.surface.day-button.range.active
#D9E9FA
calendar.color.surface.day-button.range.hover
#E3EEFA
calendar.color.surface.day-button.range.rest
#EDF3FB
calendar.color.surface.day-button.range.background
#D9E9FA
calendar.color.surface.day-button.selected.active
#00184D
calendar.color.surface.day-button.selected.hover
#004BA0
calendar.color.surface.day-button.selected.rest
#002677
calendar.color.surface.day-button.cell.range
#EDF3FB
calendar.color.text.header
#002677
calendar.color.text.day-button.disabled
#7D7F81
calendar.color.text.day-button.default
#002677
calendar.color.text.day-button.range
#002677
calendar.color.text.day-button.selected
#FFFFFF
calendar.color.text.week-days
#4B4D4F
month-year-picker.color.border.separator
#CBCCCD
month-year-picker.color.surface.container
#FFFFFF
month-year-picker.color.text.heading
#002677
calendar.border-radius.all.container
4px
calendar.border-radius.all.day-button
500px
calendar.border-width.all.container
1px
calendar.border-width.all.today
2px
month-year-picker.border-width.separator
1px
calendar.sizing.all.icon.utility
24px
calendar.spacing.gap.horizontal.footer
8px
calendar.spacing.gap.horizontal.header
8px
calendar.spacing.gap.horizontal.header-buttons
8px
calendar.spacing.padding.bottom.container
8px
calendar.spacing.padding.horizontal.container
16px
calendar.spacing.padding.vertical.footer
8px
calendar.spacing.padding.vertical.header
8px
calendar.spacing.padding.vertical.header-button
8px
calendar.spacing.padding.vertical.week-days
4px
calendar.spacing.padding.vertical.week-row
4px
month-year-picker.spacing.gap.horizontal.header
8px
month-year-picker.spacing.padding.all.header
16px
calendar.elevation.container
0px 2px 4px -2px rgba(0,0,0,0.16)

Input Tokens​

Token NameValue
input.color.surface.field.default
#FFFFFF
input.color.surface.field.highlighted
#E5F8FB
input.color.surface.field.disabled
#F3F3F3
input.color.border.field.rest
#4B4D4F
input.color.border.field.hover.default
#196ECF
input.color.border.field.hover.error
#990000
input.color.border.field.hover.success
#007000
input.color.border.field.active.default
#004BA0
input.color.border.field.active.error
#990000
input.color.border.field.active.success
#007000
input.color.text.input
#4B4D4F
input.color.text.hint
#4B4D4F
input.color.text.required
#990000
input.color.icon.utility.rest
#4B4D4F
input.color.icon.utility.hover
#323334
input.color.icon.utility.active
#000000
input.color.icon.content
#323334
input.color.cursor
#196ECF
input.border-radius.all.field
4px
input.border-width.all.field.default
1px
input.border-width.all.field.active
3px
input.sizing.all.icon
20px
input.spacing.gap.vertical.container
8px
input.spacing.gap.horizontal.field
12px
input.spacing.gap.horizontal.input-indicator
2px
input.spacing.gap.horizontal.prefix-input
2px
input.spacing.gap.horizontal.suffix-clear
2px
input.spacing.padding.all.focus-container
2px
input.spacing.padding.horizontal.field
12px
input.spacing.padding.left.field
12px
input.spacing.padding.right.focus-field
44px

Header Tokens​

Token NameValue
input-header.color.text.label
#4B4D4F
input-header.color.text.hint
#4B4D4F
input-header.color.icon.info.rest
#196ECF
input-header.color.icon.info.hover
#004BA0
input-header.color.icon.info.active
#002677
input-header.sizing.all.icon
24px
input-header.spacing.gap.horizontal.container
4px
input-header.spacing.gap.horizontal.label
4px
input-header.spacing.gap.vertical.content
4px
input-header.spacing.padding.top.content
2px

Validation Tokens​

Token NameValue
input-validation.color.surface.container
#FFFFFF
input-validation.color.text.error
#990000
input-validation.color.text.success
#007000
input-validation.color.icon.error
#990000
input-validation.color.icon.success
#007000
input-validation.sizing.all.icon
20px
input-validation.spacing.gap.horizontal.container
4px
Table of Contents