DatePicker allows a user to select a date or date range from a dropdown calendar.

Importing

The component can be imported via:

import { DatePicker } from '@customerio/pluma-components/react';

Date values

The PlumaDatePicker component uses the @internationalized/date package for handling date values. This means it expects CalendarDate instances in the value prop, and returns them in the onChange callback as well.

A CalendarDate can be created using its constructor:

import { CalendarDate } from '@internationalized/date';

// January 30, 2012
const date = new CalendarDate(2012, 1, 30);

Or by parsing an ISO 8601 formatted string with the parseDate function:

import { parseDate } from '@internationalized/date';

const date = parseDate('2012-01-30');

When withTime is enabled, the component will return ZonedDateTime instances that include time and timezone information. With isRange, it returns a start and end pair of ZonedDateTime instances.

See the CalendarDate documentation or the ZonedDateTime documentation for more details.

A native Date object can be converted to a CalendarDate like this:

const nativeDate = new Date();

const date = new CalendarDate(
	nativeDate.getFullYear(), 
	nativeDate.getMonth() + 1, 
	nativeDate.getDate()
);

A CalendarDate can be converted back to a native Date object with the toDate method, for example:

import { getLocalTimeZone } from '@internationalized/date';

const date = new CalendarDate(2012, 1, 30);
const nativeDate = date.toDate(getLocalTimeZone());

For more information, see the CalendarDate conversion docs.

Usage

To use the date picker, at a minimum you must provide the following props:

  • value
    • a CalendarDate or ZonedDateTime instance
  • onChange
    • a function, which receives a CalendarDate or ZonedDateTime instance for the date selected in the calendar
  • label

For example:

Loading editor

Date ranges

The date picker supports selecting date ranges, which can be enabled by setting the isRange prop to true.

When enabled, the value prop should be an object with start and end properties, each containing a CalendarDate instance.

Similarly, the value in the onChange callback will also be an object of that shape.

Time ranges

Set both isRange and withTime to select a range with a start time and an end time. The value is an object with start and end properties, each a ZonedDateTime in the same time zone. A new range starts as the whole selected day, from 12:00:00 AM to 11:59:59 PM. The picker calls onChange when the user clicks "Save and Close".

minRange and maxRange also accept hours, minutes, and seconds in this mode, for example "2 hours" or { minutes: 30 }. The picker shows an error and disables "Save and Close" when the range is outside these limits, or when the end time is not after the start time.

Presets also work in this mode (see Presets). A relative preset ends now. With hours, minutes or seconds it is an exact span, so timeAgo: { value: 1, unit: 'hours' } selects the last hour. With days or longer units it starts at midnight, so PLUMA_DATE_PICKER_PRESET_LAST_7_DAYS (6 days back) covers 7 calendar days, today included. The selection is whole seconds. A custom preset's callback can return ZonedDateTime values. If it returns CalendarDate values, the start becomes midnight of the start day and the end becomes the end of the end day, capped at the current time. When you do not pass presets, a range with time uses PLUMA_DATE_PICKER_DEFAULT_TIME_PRESETS: Last hour, Last 24 hours, Last 7 days, and Last 30 days.

Loading editor

Date constraints

You can constrain the selectable dates in two ways:

Using minDate and maxDate

The simplest approach is to use the minDate and maxDate props to define a valid date range. Dates outside this range will be disabled and visually indicated. Users will not be able to select dates outside the specified range.

You can use either one or both constraints:

  • Use only minDate to enforce a minimum selectable date with no upper limit
  • Use only maxDate to enforce a maximum selectable date with no lower limit
  • Use both to restrict selection to a specific date range

Both minDate and maxDate accept a CalendarDate instance:

Loading editor

You can also use just one constraint if needed:

Loading editor

These constraints also work with date ranges:

Loading editor

Using the isDateDisabled function

For more complex date constraints, you can use the isDateDisabled function prop. This gives you complete control over which dates are selectable.

The isDateDisabled function takes a CalendarDate parameter and should return true if the date should be disabled, or false if it should be enabled. It will take precedence over the minDate and maxDate props.

Loading editor

Important notes about date constraints:

  1. When using date constraints with range selection (isRange={true}), both the start and end dates must fall within the allowed range.
  2. The date constraints are enforced for both manual selection and when using presets.
  3. The constraints are visually indicated with a strikethrough style, so users can easily see which dates are unavailable.
  4. If you programmatically set a value that contains dates outside the allowed range, they will still be displayed, but the user will be unable to select new dates outside the range.
  5. Both minDate and maxDate are inclusive - users can select the exact date specified as the min/max boundary.
Loading editor

Date range presets

To make it easier to select common date ranges, the date picker supports a withPresets prop, which will render a list of presets next to the calendar.

This is only available when isRange is true.

Loading editor

Custom presets

The list of presets shown can be customized, by passing an array of preset objects into the presets prop.

A preset object can be one of two types: relative or custom.

A relative preset requires:

  • type: 'relative'
    • this key tells the date picker component to treat the preset as the "relative" type
  • label
    • a string to show in the preset button
  • timeAgo
    • an object to configure the relative date range to select when this button is clicked

timeAgo should contain two properties:

  • unit
    • a string (a key from the @internationalized/date's DateTimeDuration type), one of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'.
  • value
    • a number, the amount of unit to go back from today

A custom preset allows for more flexibility in creating the date range. It requires:

  • type: 'custom'
  • label
  • callback
    • a function that returns an object with start and end properties, each containing a CalendarDate instance. This range will be set when the preset is clicked.
    • the callback is called with an object containing the keys:
      • localTimeZone - a string representing the current time zone (either the local time zone, or the one set via the DatePicker's timeZone prop)
Loading editor

The default presets and preset types can also be imported from Pluma via:

import {
	PLUMA_DATE_PICKER_PRESET_LAST_24_HOURS,
	PLUMA_DATE_PICKER_PRESET_LAST_7_DAYS,
	PLUMA_DATE_PICKER_PRESET_LAST_30_DAYS,
	PLUMA_DATE_PICKER_PRESET_LAST_365_DAYS,
	// Selects the last 12 weeks, ending on today (included)
	PLUMA_DATE_PICKER_PRESET_LAST_12_WEEKS_FROM_NOW,
	// Selects the last 12 weeks, where each week starts on a Sunday
	PLUMA_DATE_PICKER_PRESET_LAST_12_FULL_WEEKS_SUNDAY_START,
	// An array containing the default presets used by the datepicker
	PLUMA_DATE_PICKER_DEFAULT_PRESETS,
	// The default presets used when `isRange` and `withTime` are both set
	PLUMA_DATE_PICKER_DEFAULT_TIME_PRESETS,
} from '@customerio/pluma-components/react/date-picker'
import type {
	PlumaDatePickerPresetRelative,
	PlumaDatePickerPresetCustom,
	PlumaDatePickerPreset,
} from '@customerio/pluma-components/react/date-picker'

Preset icons, tooltips and actions

Both preset types accept three optional keys:

  • icon - the name of an icon to show after the label
  • tooltip - text to show in a tooltip when the preset is hovered or focused
  • onClick - a function to call when the preset is clicked, instead of selecting its range. It is called with an object containing close, a function that closes the date picker. Use it for a preset that starts another action, for example a range the account cannot use yet, where a click opens a modal to upgrade. minDate, maxDate and isDateDisabled do not disable a preset with onClick, because it does not select its range. A preset disabled with isPresetDisabled does not call onClick.
Loading editor

Enabling/disabling presets

By default, presets will be automatically disabled if their resulting date range falls (even partially) outside the date constraints set by minDate and maxDate. However, sometimes it's desirable to have the presets enabled anyway, allowing the selection of partial ranges.

The isPresetDisabled boolean can control this behavior. It can receive either:

  • a boolean value, which will apply to all presets
  • a function, which receives a preset object and its current calculated range, and should return a boolean indicating whether the preset should be disabled
Loading editor

Range length limits

By default, the date picker allows selecting a range of any length - including a single day. To enforce a minimum and/or maximum range length, the minRange and maxRange props can be used.

Both props accept multiple formats:

  • numbers - interpreted as a number of days
  • strings - strings of form "{quantity} {unit}", where unit is one of: days, weeks, months, years (e.g. "6 months", "2 weeks"). With withTime, the unit can also be hours, minutes, or seconds (see Time ranges)
  • an @internationalized/date DateTimeDuration object
Loading editor

Time zones

By default, PlumaDatePicker will use the user's local time zone when working with dates: most importantly, determining what "today" is for pre-selecting today's date, calculating relative ranges etc.

However, sometimes it's necessary to show a DatePicker that refers to dates in a different time zone. To make sure the component handles disabled dates, presets, etc correctly, a localTimeZone string prop can be provided.

The time zone string is passed into Intl API calls, and should be an IANA time zone name. If an invalid time zone is provided, it will fall back to @internationalized/date's getLocalTimeZone function.

Loading editor

Customizing labels

If a string label is not sufficient, a component can be used to render the label.

In React, the label prop accepts any ReactNode.

Loading editor

Customizing descriptions

If a string description is not sufficient, a component can be used to render the description.

In React, the description prop accepts any ReactNode.

Loading editor

Customizing errors

If a string error is not sufficient, a component can be used to render the error.

In React, the error prop accepts any ReactNode.

Loading editor

API

Default:'input'

What element or component should be rendered.

Whether the date picker should render in the open state.

Function to determine if a date is disabled and cannot be selected. This takes precedence over minDate and maxDate if provided.

By default, a preset will become disabled if its range cannot be fully selected (based on dates being disabled via minDate and maxDate). A preset with onClick is not disabled this way, because it does not select its range. This allows overriding that behavior to enable/disable presets conditionally, or keep them always enabled. If a function is provided, it will be called with the preset and its calculated range, and should return a boolean. If the value is a boolean, it will apply to all presets.

Whether the date picker should select date ranges. Combine with withTime to select a range with a start time and an end time.

By default, the DatePicker uses the user's local time zone for calculating dates like "today". If the date picker represents dates in a different time zone, a time zone name can be provided here.

The maximum selectable date.

The maximum range length that must be selected. By default, there is no maximum range length. It accepts multiple formats:

  • numbers - interpreted as a number of days
  • strings - strings of form "quantity unit", where unit is one of: days, weeks, months, years (e.g. "6 months", "2 weeks"). With withTime, the unit can also be hours, minutes, or seconds (e.g. "2 hours", "30 minutes")
  • an @internationalized/date DateTimeDuration object

The minimum selectable date.

The minimum length of a time range that must be selected. By default, there is no minimum range length (essentially 0 - same day selection allowed). It accepts multiple formats:

  • numbers - interpreted as a number of days
  • strings - strings of form "quantity unit", where unit is one of: days, weeks, months, years (e.g. "6 months", "2 weeks"). With withTime, the unit can also be hours, minutes, or seconds (e.g. "2 hours", "30 minutes")
  • an @internationalized/date DateTimeDuration object

The duration (in ms) for the popover animation.

An array of presets to render instead of the default ones.

Default:true

Whether the calendar should automatically focus when it first renders.

Default:true

Whether the open popover traps focus and hides the rest of the page from assistive technology, as a modal dialog does. Turn it off only where the popover is shown as an illustration beside other content, such as a documentation page.

Additional inline styles to apply on the popover component (the floating element, not the trigger). Should only be used as a last resort

Whether the date picker should show preset selection. Only available when isRange is true.

Default:false

Whether to include time selection in the picker. With isRange, the picker selects a start time and an end time.

An icon to show after the label, aligned to the end of the preset button.

The text to show for the preset button.

Called when the preset is clicked, instead of selecting its range. Use it for a preset that starts another action, like opening a modal. minDate, maxDate and isDateDisabled do not disable a preset with onClick. A preset disabled with isPresetDisabled does not call it.

The time period (from now into the past) to select. unit is an @internationalized/date DateTimeDuration key, one of: 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'. value is how many of that unit to go back.

Text to show in a tooltip when the preset button is hovered or focused.

The type of preset.

A callback function that returns the start and end dates for the preset. The dates must be @internationalized/date CalendarDates or, for pickers with withTime, ZonedDateTimes. With withTime, CalendarDate results are converted: the start becomes the start of its day, and the end becomes the end of its day, capped at the current time.

An icon to show after the label, aligned to the end of the preset button.

The text to show for the preset button.

Called when the preset is clicked, instead of selecting its range. Use it for a preset that starts another action, like opening a modal. minDate, maxDate and isDateDisabled do not disable a preset with onClick. A preset disabled with isPresetDisabled does not call it.

Text to show in a tooltip when the preset button is hovered or focused.

The type of preset.