This enables merchants to type a specific date or pick it from a calendar.
How it helps merchants
- The text input gives merchants the option to use the keyboard to enter a date.
- 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.
-
This pattern can be duplicated to allow users to add an end date or time.
Related resources
- Programming timezones can be finicky. Get great tips in the article UTC is for everyone right?
- Learn about date formatting in the Grammar and mechanics guidelines.
- See how to craft effective button labels in the Actionable language guidelines.