Skip to contentSkip to navigationSkip to topbar
Figma
Star

Date Picker

Version 6.1.1GithubStorybookPeer review pending

A Date Picker is a form element used to select a date.

Component preview theme
const LabelOnlyPicker = (props) => {
const uidDP = useUID();
return (
<>
<Label htmlFor={uidDP}>When does this year&apos;s LGBTQ+ Pride month begin in the US?</Label>
<DatePicker id={uidDP} {...props} />
</>
);
}
render(<LabelOnlyPicker />)

Guidelines

Guidelines page anchor

About Date Picker

About Date Picker page anchor

The Date Picker is an input field which accepts a value in MM/DD/YYYY format.

Currently, the Date Picker is built on top of the HTML date picker(link takes you to an external page), using an input field with type="date", which comes with some inherent limitations. In order to release a functional and stable Date Picker for immediate use, we decided to work within these limitations with the intention of updating this package to a custom Date Picker in a future release. The current API was designed to avoid any breaking changes with future versions of the Date Picker.

It is used with the Label and Help Text components.

Because browsers' implementations of the native date picker vary, this component may not be fully accessible in all cases. Chrome/Edge, Safari and Firefox all support the Date Picker, but the user experience differs browser-to-browser. Some of those differences are outlined below:

Chrome/Edge
  • Default value is "mm/dd/yyyy"
  • Calendar pop-up is triggered by clicking on the calendar icon - clicking on the input field places focus on the value
  • "Today" button selects current date and closes calendar pop-up
Chrome/Edge implementation of date picker
Safari
  • Default value is the current date
  • Clicking on the input field triggers the calendar pop-up and places focus on the value (calendar icon not present)
  • Circular button (in between navigation left/right arrows) navigates calendar pop-up back to selected date
Safari implementation of date picker
Firefox
  • Default value is "mm/dd/yyyy"
  • Clicking on the input field triggers the calendar pop-up and places focus on the value (calendar icon not present)
  • No functionality to navigate user back to current or selected date
Firefox implementation of date picker

While cross-browser functionality, style and accessibility differences are present, they will not affect the usability of the Date Picker. The API is stable and full usage of the component is encouraged. There are certain use cases not included in the input type="date" functionality, such as a date range picker. You can find examples of how to recreate those use cases below. If there's a Date Picker use case not covered by the current implementation, feel free to open a Discussion(link takes you to an external page) so that we can help you find a solution.

  • Include a visible label on all Date Pickers.
  • Each label must use the htmlFor prop that matches the id of the associated input.
  • Use one of 3 ways to label a Date Picker:
    • Visible label with Label (preferred)
    • Visible label that's associated to the Date Picker with aria-labelledby
    • Label directly using aria-label
  • Provide clear identification of required fields in the label or at the start of a form. If you use the required field indicator, include the form key at the start of the form.
    • Use the required prop to programatically indicate they are required to browsers.
  • Include inline error text with the error icon on any field that errors to make it visually clear that the field changed.
  • If the Date Picker has associated help text or error text, include the aria-describedby prop on the Date Picker. This should match the id of the help or error text.

The Date Picker component should include the base DatePicker, along with supporting elements to compose an input field that gives users the context they need to successfully fill it out.

  • Label — A label should be included for every Date Picker and provide a short title for its associated input.
  • Required field indicator — In a form where there are fewer or as many required fields as optional, use a required indicator to show users which fields are required to be filled out.
  • Help text — Text that's placed below the field to help users prevent an error and describe what makes the Date Picker input successful.
(information)

Make sure to connect the Label to the DatePicker. This is done with the htmlFor prop on the label, and the id prop on the Date Picker. Those two need to match.

If the Date Picker has any associated help text, it should also use the aria-describedby prop that equals the id of the help text. This ensures screen readers know the help text ties directly to the Date Picker.

Component preview theme
const RequiredDatePicker = (props) => {
const uidDP = useUID();
const uidHT = useUID();
return (
<>
<Label htmlFor={uidDP} required>
When was the abolition of slavery announced in Galveston Bay, Texas (also known as Juneteenth)?
</Label>
<DatePicker required id={uidDP} aria-describedby={uidHT} {...props} />
<HelpText id={uidHT}>
Enter a date above.
<Anchor href="https://nmaahc.si.edu/blog-post/historical-legacy-juneteenth" showExternal>
Read more about Juneteenth
</Anchor>
</HelpText>
</>
);
};
render(<RequiredDatePicker />)

The Date Picker doesn't currently support the selection of date ranges within a single input field, however a date range picker can be easily implemented using two side-by-side Date Pickers. For further validation, use the value of the start Date Picker as the min for the end Date Picker.

Component preview theme
const DateRangePicker = (props) => {
const [startDate, setStartDate] = React.useState('');
const startUidDP = useUID();
const endUidDP = useUID();
return (
<Stack orientation="horizontal" spacing="space80">
<Box>
<Label htmlFor={startUidDP}>Start date</Label>
<DatePicker id={startUidDP} onChange={(evt) => setStartDate(evt.target.value)} {...props} />
</Box>
<Box>
<Label htmlFor={endUidDP}>End date</Label>
<DatePicker id={endUidDP} min={startDate} {...props} />
</Box>
</Stack>
);
}
render(<DateRangePicker />)

Paste pickers don't currently support date time range selections in a single component, however the same functionality can be implemented using a combobox along with the date range and time range picker solutions. If you'd like to provide your users with pre-determined options before displaying the pickers, use the following example as a jumping off point.

Component preview theme
const DateTimeRangePicker = (props) => {
const [selectedItem, setSelectedItem] = React.useState('')
const uidStartDP = useUID();
return selectedItem === "Custom" ? (
<>
<Box margin="space60">
<Label htmlFor="uidStartDP">Date range</Label>
</Box>
<Stack orientation="horizontal" spacing="space80">
<Box marginLeft="space60">
<DatePicker id="uidStartDP" aria-describedby="start-date" />
<HelpText id="start-date">Start date</HelpText>
</Box>
<Box>
<TimePicker aria-describedby="start-time" />
<HelpText id="start-time">Start time</HelpText>
</Box>
</Stack>
<Stack orientation="horizontal" spacing="space80">
<Box marginLeft="space60" marginTop="space60">
<DatePicker aria-describedby="end-date" />
<HelpText id="end-date">End date</HelpText>
</Box>
<Box marginTop="space60">
<TimePicker aria-describedby="end-time" />
<HelpText id="end-time">End time</HelpText>
</Box>
</Stack>
</>
) : (
<Box margin="space60">
<Combobox
insertAfter={<CalendarIcon color="colorTextIcon" decorative />}
items={["Last 7 days", "Last 30 days", "Last 6 months", "Custom"]}
labelText="Date range"
onSelectedItemChange={(changes) => {
setSelectedItem(changes.selectedItem)
}}
/>
</Box>
)
}
render(<DateTimeRangePicker />)

In addition to the Date Picker, this package exports a formatReturnDate() function that can be used to format the date value that's being returned from the Date Picker.

Note: the format of the date being displayed by the Date Picker cannot be changed. The display value is formatted according to the locale of the user's browser(link takes you to an external page). The parsed value, however, is always returned in yyyy-mm-dd format.

To change the format of the return date value, we recommend using the formatReturnDate() function on the Date Picker's onChange() or onBlur() handler.

The function accepts two parameters: (1) the date value that should be formatted (e.g. '2021-03-24'), and (2) the desired date format (e.g. 'MM dd yyyy'). It uses a library called date-fns(link takes you to an external page) to return the given date in the desired format. Date format must follow the tokens outlined by date-fns(link takes you to an external page).

Component preview theme
const OnChangePicker = (props) => {
const [value, setValue] = React.useState('');
const [dateFormat, setDateFormat] = React.useState('MM dd yy');
const uidDP = useUID();
const uidHT = useUID();
const dateFormatOptions = ['MM dd yyyy', 'MMMM do yyyy', 'EEEEEE MMM do yy', 'MM/dd/yyyy'];
const handleChange = (val, format) => {
setValue(formatReturnDate(val, format));
return value;
};
return (
<>
<Box marginBottom="space60">
<Combobox
items={dateFormatOptions}
labelText="Return date format:"
onInputValueChange={({inputValue}) => {
if (inputValue !== undefined) setDateFormat(inputValue);
}}
/>
</Box>
<Label htmlFor={uidDP}>On what day was Apartheid legislation repealed in South Africa?</Label>
<DatePicker
id={uidDP}
aria-describedby={uidHT}
onChange={(evt) => handleChange(evt.target.value, dateFormat)}
{...props}
/>
<HelpText id={uidHT}>
Enter a date above.
<Anchor href="https://www.sahistory.org.za/article/history-apartheid-south-africa" showExternal>
Read more about Apartheid in South Africa
</Anchor>
</HelpText>
<Box marginTop="space60">
<b>Return value </b>(will only change when the onChange event fires): {value}
</Box>
</>
);
}
render(<OnChangePicker />)

DatePicker with inline error

DatePicker with inline error page anchor

Change a Date Picker to its error state and use Help Text to add an inline error if the value entered doesn't pass validation requirements.

Use Help Text to place an inline error is placed below the field to inform a user of any errors in their value. If help text exists, the error text should replace and repeat the help text.

Component preview theme
const HasErrorPicker = (props) => {
const uidDP = useUID();
const uidHT = useUID();
return (
<>
<Label htmlFor={uidDP}>When did the Jallianwala Bagh massacre take place?</Label>
<DatePicker id={uidDP} aria-describedby={uidHT} hasError {...props} />
<HelpText id={uidHT} variant="error">
Enter a date above.
<Anchor
href="https://www.hindustantimes.com/india-news/jallianwala-bagh-massacre-here-is-how-the-deadly-incident-transpired-102-years-ago-101618276752335.html"
showExternal
>
Read more about the Jallianwala Bagh massacre
</Anchor>
</HelpText>
</>
);
}
render(<HasErrorPicker />)

Use a disabled Date Picker to show users that they can't interact with it.

If you want to show information that can't be edited, use a read-only field or consider another way of showing static information.

Component preview theme
const DisabledPicker = (props) => {
const uidDP = useUID();
const uidHT = useUID();
return (
<>
<Label htmlFor={uidDP} disabled>
When did the Supreme Court ban anti-miscegenation laws (in Loving v. Virginia)?
</Label>
<DatePicker id={uidDP} aria-describedby={uidHT} disabled defaultValue="1967-06-12" {...props} />
<HelpText id={uidHT}>
<Anchor href="https://www.oyez.org/cases/1966/395" showExternal>
Read more about Loving Day
</Anchor>
</HelpText>
</>
);
}
render(<DisabledPicker />)

Use a read-only Date Picker when a its value can't be changed, but users should be able to read or apply focus on it.

Component preview theme
const ReadOnlyPicker = (props) => {
const uidDP = useUID();
const uidHT = useUID();
return (
<>
<Label htmlFor={uidDP}>In what month was the Combahee River Collective (CRC) Statement published?</Label>
<DatePicker id={uidDP} aria-describedby={uidHT} readOnly defaultValue="1977-04-01" {...props} />
<HelpText id={uidHT}>
{' '}
<Anchor href="https://combaheerivercollective.weebly.com/" showExternal>
Read more about the CRC
</Anchor>{' '}
</HelpText>
</>
);
}
render(<ReadOnlyPicker />)

A Date Picker must have at least a label and an input.

Component preview theme
const LabelOnlyPicker = (props) => {
const uidDP = useUID();
return (
<>
<Label htmlFor={uidDP}>When does this year&apos;s LGBTQ+ Pride month begin in the US?</Label>
<DatePicker id={uidDP} {...props} />
</>
);
}
render(<LabelOnlyPicker />)
(information)

Quick note about Date Picker DOM methods

There are three methods that come with the HTML picker: stepUp(), stepDown() and select(). Usage of these methods is possible, but we do not encourage it, as they may not be supported in future versions of the Date Picker. Use at your own risk!

Positioning Date Pickers

Positioning Date Pickers page anchor

When using multiple Date Pickers, stack them vertically with $space-80 spacing between each field. To stack them, you can use either a Box or a Stack (as seen in the example below).

Component preview theme
const StackOfPickers = (props) => {
const uidDPOne = useUID();
const uidHTOne = useUID();
const uidDPTwo = useUID();
const uidHTTwo = useUID();
return (
<Stack orientation="vertical" spacing="space80">
<Box>
<Label htmlFor={uidDPOne}>When was the NAACP Legal Defense Fund (LDF) founded?</Label>
<DatePicker id={uidDPOne} aria-describedby={uidHTOne} {...props} />
<HelpText id={uidHTOne}>
Enter a date above.
<Anchor href="https://www.naacpldf.org/about-us/history/" showExternal>
Read more about the NAACP LDF
</Anchor>
</HelpText>
</Box>
<Box>
<Label htmlFor={uidDPTwo}>
When did Thurgood Marshall become the first African American Supreme Court Justice?
</Label>
<DatePicker id={uidDPTwo} aria-describedby={uidHTTwo} {...props} />
<HelpText id={uidHTTwo}>
Enter a date above.
<Anchor
href="https://constitutioncenter.org/blog/thurgood-marshalls-unique-supreme-court-legacy"
showExternal
>
Read more about Marshall&apos;s legacy
</Anchor>
</HelpText>
</Box>
</Stack>
);
}
render(<StackOfPickers/>)

Avoid placing multiple pickers on the same horizontal row to help make it easier to scan a page vertically. Use a Grid if you need to place them horizontally.

Labels should clearly describe the date value being requested. They should be concise and descriptive, not instructional. To do this:

  • Use help text to provide instruction if needed. For example, don't use "Enter the date you wish to receive your bill below" as label text. Instead, use "Billing date" as a label and "Your account will be automatically billed on the above date." as help text.
  • Avoid articles ("a", "the") and punctuation. For example, use "SIM registration code" rather than "The SIM registration code".

To support internationalization, avoid starting a sentence with the label and using the field to finish it since sentence structures vary across languages. For example, use "Call log expiration date" or "How long should logs be stored?". Don't use "Remove logs after:".

Required field indicator

Required field indicator page anchor

Use required indicators to show users which fields they must fill out.

Component preview theme
const RequiredDatePicker = (props) => {
const uidDP = useUID();
const uidHT = useUID();
return (
<>
<Label htmlFor={uidDP} required>
When was the abolition of slavery announced in Galveston Bay, Texas (also known as Juneteenth)?
</Label>
<DatePicker required id={uidDP} aria-describedby={uidHT} {...props} />
<HelpText id={uidHT}>
Enter a date above.
<Anchor href="https://nmaahc.si.edu/blog-post/historical-legacy-juneteenth" showExternal>
Read more about Juneteenth
</Anchor>
</HelpText>
</>
);
};
render(<RequiredDatePicker />)

Validate Date Picker fields on form submission.

Validating a field input when the user leaves the current field (on blur) can be helpful to check for syntax errors. However, this can be frustrating to users who tab through controls to navigate a page, and to screen reader users, who might not be able to detect that an error occurred on blur.

Don't prevent form submission by disabling the submit button. A disabled button cannot be detected by assistive technologies. Use error messages to explain what information is missing or incorrect.

Usage of the min and max properties on Date Picker is encouraged if certain dates are invalid.

Component preview theme
const MinAndMaxPicker = (props) => {
const uidDP = useUID();
const uidHT = useUID();
return (
<>
<Label htmlFor={uidDP}>When was Grace Hopper awarded the Presidential Medal of Freedom?</Label>
<DatePicker id={uidDP} aria-describedby={uidHT} min="2016-10-15" max="2016-10-25" {...props} />
<HelpText id={uidHT}>
Hint: it was awarded posthumously by President Obama.
<Anchor
href="https://news.yale.edu/2017/02/10/grace-murray-hopper-1906-1992-legacy-innovation-and-service"
showExternal
>
Read more about Grace Hopper
</Anchor>
</HelpText>
</>
);
}
render(<MinAndMaxPicker />)

Use Help Text to show inline error text that explains how to fix an error.

Help text should have enough information to help users prevent errors. If help text exists and you need to show an error, the error text should replace and repeat the help text until the error has been resolved.

For additional guidance on how to compose error messages, refer to the error state pattern.

(information)

Date Picker and placeHolder

Because Date Picker has a default display value of mm/dd/yyyy (and defaults to the current date on Safari), any value that gets passed into placeholder will be overwritten (and effectively ignored).