Skip to main content
On this page

A form field for entering a date, with an optional calendar popup for selection

When to use​

  • When the user needs to enter a date that is in the recent past or near future, where seeing a calendar helps them pick the right day
  • When the user might copy the date from another source (such as a letter or document) and type it directly
  • When the date relates to a booking, appointment, or event where surrounding context (day of the week, proximity to today) matters

When not to use​

  • For historical dates the user knows from memory, such as date of birth or passport issue date. The calendar offers no benefit and navigating back years is tedious. Use DateField instead.
  • For dates far in the future where the user would need to navigate many months forward. Consider a Text Field with clear format instructions if the date range is very large.
  • To indicate that a field is unavailable - the disabled state is not supported. Use Summary List to show values that cannot be edited, or conditionally hide the field if it is not relevant in the current context.

Anatomy​

  1. Label
  2. Required/Optional indicator
  3. Hint (optional; describe constraints such as the available date range rather than the input format)
  4. Input (accepts a date typed in dd/mm/yyyy format)
  5. Calendar button (opens the calendar popup)
  6. Error message
  7. Calendar popup (contains month navigation, a day grid, a today button, and a clear button)
  8. Today indicator (highlights today's date in the calendar grid)

Basic usage​

Loading...
Edit live code
<DatepickerField
  id="date"
  label="Date"
/>

Variants and features​

OverlayProvider wrapper​

DatepickerField requires an OverlayProvider wrapper to position the calendar popup correctly and make it accessible. Wrap the page or section that contains the datepicker, not each individual field.

Without it the popup is not accessible: the page behind the calendar is not hidden from screen readers, so assistive technology users can read content they cannot interact with.

This example is not live, because the docs site provides its own OverlayProvider around every page.

import { OverlayProvider } from '@react-aria/overlays';

<OverlayProvider>
{/* One per page or section, not one per field */}
<DatepickerField id="start-date" label="Start date" />
<DatepickerField id="end-date" label="End date" />
</OverlayProvider>

Typing a date directly​

Users can type a date directly into the input without opening the calendar. The expected format is dd/mm/yyyy. The placeholder shows this format automatically.

The calendar updates to reflect the typed value as soon as it parses as a valid date.

Unavailable dates​

Use the isDateUnavailable prop to mark specific dates as unavailable in the calendar. Unavailable dates are still visible but cannot be selected.

This does not stop a date being typed into the input, so always validate on submit as well.

Loading...
Edit live code
<DatepickerField
  id="appointment-date"
  label="Appointment date"
  hint="Weekdays only"
  isDateUnavailable={date => date.getDay() === 0 || date.getDay() === 6}
/>

Validating the selected date​

Use the exported getDatepickerDate utility to parse the field's string value into a Date object. It returns null if the value is not a valid date.

Loading...
Edit live code
() => { // ignore - for live code example only.
  const Example = () => {
    const [errors, setErrors] = useState([]);

    const onSubmit = (e) => {
      e.preventDefault();
      const newErrors = [];

      const { datepicker } = Object.fromEntries(new FormData(e.currentTarget));

      const datepickerDate = getDatepickerDate(datepicker)

      if (!datepickerDate) {
        newErrors.push({ id: 'datepicker', message: 'Enter a valid date in the format dd/mm/yyyy'});
      }

      setErrors(newErrors);

      if (!newErrors.length) {
        alert('success');
      }
    }

    return (
      <Form errors={errors} onSubmit={onSubmit} noValidate>
        <FormFields>
          <DatepickerField
            id="datepicker"
            name="datepicker"
            label="Datepicker example"
          />
        </FormFields>
        <FormActions>
          <PrimaryCTAButton type="submit">Validate date</PrimaryCTAButton>
        </FormActions>
      </Form>
    );
  }

  return <Example />;
}

Date ranges​

DatepickerField does not have a built-in date range mode. To collect a start and end date, place two DatepickerField components side by side. Use isDateUnavailable on the second field to prevent the user from selecting a date before the first.

Align the two fields to the bottom of their container so the inputs stay aligned when one has hint text or an error.

Loading...
Edit live code
() => { // ignore - for live code example only.
  const Example = () => {
    const [startDate, setStartDate] = useState('');

    const isDateUnavailable = (date) => {
      const start = getDatepickerDate(startDate);
      if (!start) {
        return false;
      }
      return date.getTime() < start.getTime();
    };

    return (
      <div style={{ display: 'flex', gap: '1.2rem', alignItems: 'flex-end' }}>
        <DatepickerField
          id="range-start-date"
          name="range-start-date"
          label="Start date"
          hint="On or after this date"
          onChange={setStartDate}
        />
        <DatepickerField
          id="range-end-date"
          name="range-end-date"
          label="End date"
          isDateUnavailable={isDateUnavailable}
        />
      </div>
    );
  }

  return <Example />;
}

Common form features​

The following features are shared across all Nebula form fields. See Form guidance for full detail.

Validation and errors: when a field is invalid, an error message appears below the input. Use getDatepickerDate to check whether the string value is a valid date before deciding whether to show an error.

Hint text: use hint text to describe date constraints (for example, "Within the next 28 days"), not the input format. The placeholder already shows dd/mm/yyyy.

Required and optional: fields are required by default. Use the optional prop to mark a field as optional.

Field width: DatepickerField defaults to a fixed width that fits the dd/mm/yyyy format. Use fullWidth to control responsive behaviour.