Date picking

Lets merchants select a date or a date range

Discuss on GitHub

This enables merchants to type a specific date or pick it from a calendar.

How it helps merchants

Date text input and a single-month calendar
  1. The text input gives merchants the option to use the keyboard to enter a date.
  2. A single month calendar allows merchants to select a date while seeing its relationship to other days.

Use when merchants need to:

Schedule an event on a specific day
Some examples of this are setting a visibility date for a new online store page, or an estimated arrival date for a shipment. Found in: Product / transfers
Input memorable dates to forms
An example of this is entering a birthdate.

Using this pattern

This pattern uses the Card, DatePicker, Popover and TextField components.

// This example is for guidance purposes. Copying it will come with caveats.
function DatePickerExample() {
  function nodeContainsDescendant(rootNode, descendant) {
    if (rootNode === descendant) {
      return true;
    }
    let parent = descendant.parentNode;
    while (parent != null) {
      if (parent === rootNode) {
        return true;
      }
      parent = parent.parentNode;
    }
    return false;
  }
  const [visible, setVisible] = useState(false);
  const [selectedDate, setSelectedDate] = useState(new Date());
  const [{ month, year }, setDate] = useState({
    month: selectedDate.getMonth(),
    year: selectedDate.getFullYear(),
  });
  const formattedValue = selectedDate.toISOString().slice(0, 10);
  const datePickerRef = useRef(null);
  function isNodeWithinPopover(node) {
    return datePickerRef?.current
      ? nodeContainsDescendant(datePickerRef.current, node)
      : false;
  }
  function handleInputValueChange() {
    console.log("handleInputValueChange");
  }
  function handleOnClose({ relatedTarget }) {
    setVisible(false);
  }
  function handleMonthChange(month, year) {
    setDate({ month, year });
  }
  function handleDateSelection({ end: newSelectedDate }) {
    setSelectedDate(newSelectedDate);
    setVisible(false);
  }
  useEffect(() => {
    if (selectedDate) {
      setDate({
        month: selectedDate.getMonth(),
        year: selectedDate.getFullYear(),
      });
    }
  }, [selectedDate]);
  return (
    <BlockStack inlineAlign="center" gap="400">
      <Box minWidth="276px" padding={{ xs: 200 }}>
        <Popover
          active={visible}
          autofocusTarget="none"
          preferredAlignment="left"
          fullWidth
          preferInputActivator={false}
          preferredPosition="below"
          preventCloseOnChildOverlayClick
          onClose={handleOnClose}
          activator={
            <TextField
              role="combobox"
              label={"Start date"}
              prefix={<Icon source={CalendarIcon} />}
              value={formattedValue}
              onFocus={() => setVisible(true)}
              onChange={handleInputValueChange}
              autoComplete="off"
            />
          }
        >
          <Card ref={datePickerRef}>
            <DatePicker
              month={month}
              year={year}
              selected={selectedDate}
              onMonthChange={handleMonthChange}
              onChange={handleDateSelection}
            />
          </Card>
        </Popover>
      </Box>
    </BlockStack>
  )
}

Useful to know

  • Labels need to simply depict the task at hand. Whether that be a start date, end date, start time etc.

    Date input labeled “Expiry date”
  • This pattern can be duplicated to allow users to add an end date or time.

    “Active dates” section with “start date” and “end date” inputs, toggled on with a “Set end date” checkbox

    On this page