Appearance
Date Range
Capture a start and an end date from a single calendar — for bookings, rentals, hire periods, and delivery windows.
Overview
Date Range sits alongside the existing Date type rather than replacing it: Date captures one day, Date Range captures a span — and knows how long that span is.
The customer sees two read-only fields. Clicking either opens one calendar: the first click sets the start, the second sets the end.
Use Date Range for:
- Equipment and vehicle hire
- Accommodation and stay bookings
- Rental periods
- Delivery or service windows
Key characteristics:
- Dates are stored as
YYYY-MM-DDand written to the cart as one property - Knows its own length, in either days or nights
- Can be marked as required
- Works as a condition source, evaluated against the whole span
- Unavailable days are greyed out rather than silently rejected
Pricing is not part of this option type
Date Range captures a span and its length. It does not price that span — there's no per-day or per-night rate here. Use Price Add-Ons for pricing, or read the hidden duration property from your theme (see Cart Properties).
Configuration
Basic Settings
| Setting | Description |
|---|---|
| Label | Option name displayed to customers (e.g., "Hire period") |
| Option is required for this option set | If enabled, customers must pick a range before adding to cart |
| Hide Label from storefront | If enabled, only the two fields are shown |
The option's settings card is grouped into four sections: Duration, Availability, Booking window, and Labels.
Duration
| Setting | Options (default) | What it controls |
|---|---|---|
| Count as | days (default) / nights | Days counts both the first and last date; nights counts the stays between them. 1st → 7th is 7 days or 6 nights — hire versus hotel |
| Minimum duration | number (empty) | The shortest range a customer can select. Leave empty for no limit |
| Maximum duration | number (empty) | The longest range a customer can select. Leave empty for no limit |
Availability
| Setting | Options (default) | What it controls |
|---|---|---|
| Available dates | All dates (default) / All dates except… / Only specific dates | Choose whether customers can pick any date, or only some. The fields below switch with this |
| Blocked days of the week | seven toggles (none) | Shown under All dates except… — greys that weekday on every occurrence, every month |
| Blocked dates | list of dates (empty) | Specific dates customers cannot select, such as holidays or closures |
| Available periods | list of ranges (empty) | Shown under Only specific dates — only dates inside these periods can be selected |
| Available individual dates | list of dates (empty) | Single dates that can be selected, on top of any periods above |
Booking window
| Setting | Options (default) | What it controls |
|---|---|---|
| Disable past dates | toggle (on) | Customers cannot select a date earlier than today |
| Earliest date | No limit (default) / Specific date / Days from today | The relative mode is lead or prep time — blocks dates within this many days of the order date |
| Latest date | No limit (default) / Specific date / Days from today | How far ahead customers can book |
"Days from today" is a rolling window
Set Earliest date → Days from today = 5 and today through today+4 are greyed; today+5 is the first selectable day. The window moves with the calendar, so you never have to update a fixed date.
Labels
| Setting | Options (default) | What it controls |
|---|---|---|
| Start field label | text (empty, hint Check in) | The label on the first field |
| End field label | text (empty, hint Check out) | The label on the second field |
Advanced Settings
| Setting | Description |
|---|---|
| Internal Label | Admin-only identifier (replaces label in the options list) |
| Help Text | Additional guidance shown to customers (based on display mode) |
| CSS class / CSS ID | Your own selectors on this option's container — see CSS Class & CSS ID |
Date format and separator live on the template
How dates are displayed — the format and the separator between them — is a styling setting on the assigned Customization template, not on the option. Stored dates are always ISO. See Types Settings.
Validation
Nothing turns red until you press Save
Choosing "Days from today" and leaving the offset empty for a moment doesn't flag an error. Validation runs on save, so the form doesn't scold you mid-edit.
| Message | Cause |
|---|---|
| The maximum must be greater than or equal to the minimum. | Minimum duration exceeds Maximum duration |
| Enter a whole number of 1 or more. | A duration is zero, negative, or fractional |
| That duration is too long. | A duration is oversized |
| The latest date must be on or after the earliest date. | Latest date precedes Earliest date |
| The latest offset must be greater than or equal to the earliest offset. | Latest "days from today" is below Earliest's |
| Choose a date. | A date is missing for the chosen mode |
| Enter a number of days. | An offset is missing for the chosen mode |
| Enter a valid date. | A date field isn't a valid date |
| Add at least one available period or date, or no date can be selected. | Only specific dates with an empty allow-list |
| Every day of the week is blocked, so no date can be selected. | All seven weekday toggles are on |
How to Add a Date Range
- Navigate to Option Sets and open your option set
- Click Add Option
- Select Date Range from the Option Type modal (it's under the Input category)
- Enter a Label (e.g., "Hire period")
- Under Duration, choose Count as and set a minimum or maximum if you need one
- Under Availability, restrict dates if some are closed
- Under Booking window, set lead time and how far ahead customers can book
- Under Labels, name the two fields (e.g., "Check in" and "Check out")
- (Optional) Click Advanced Settings for an Internal Label, Help Text, or a CSS class/ID
- Click Save in the contextual save bar
How Customers Pick a Range
- First click sets the start and marks it selected immediately; the end stays empty
- Hovering after that previews the span — the hovered day takes the end colour, the days between take the in-range colour
- Second click completes the range and closes the calendar (unless the template renders it inline)
- Clicking on or before the start restarts the range from there
- With a range already complete, the next click starts a new range rather than stretching the old one
- A same-day range is allowed when no minimum forbids it — 1 day, or 0 nights
What gets greyed out
Unavailable days stay visible and readable by screen readers; only their styling changes.
- Past dates, when Disable past dates is on
- Blocked weekdays, on every occurrence in every month
- Dates outside the booking window
- Everything outside the allow-list, under Only specific dates
- Once a start is chosen: any day that cannot legally end the range under your min/max duration. The start itself and everything before it stay clickable
A range can't span a closed day
If a blocked date sits between the start and a candidate end, that end is unavailable — a hire can't run straight through a day you're shut.
If a chosen start leaves no bookable end at all — say a 3-night minimum starting Friday with the weekend closed — the summary says so rather than asking for an end date that can't exist.
Accessibility
The calendar is a role="grid": arrow keys move day to day, and the grid holds exactly one tab stop. Unavailable days use aria-disabled, so they're still reachable and announced rather than hidden. Choosing a start announces that an end is wanted; completing the range announces its length.
Cart Properties
A completed range produces one visible property plus three hidden ones:
| Property | Example | Notes |
|---|---|---|
Hire period | 12/08/2026 – 15/08/2026 | Visible on the cart line, using the template's date format and separator |
_Hire period start | 2026-08-12 | Hidden, always ISO |
_Hire period end | 2026-08-15 | Hidden, always ISO |
_Hire period days (or nights) | 4 | Hidden, named after the option's Count as setting |
The hidden properties are there so you don't have to parse the visible one
Shopify hides _-prefixed properties from the cart but keeps them on the order. Read them in Liquid or from the Admin API to get the machine-readable start, end, and length — no need to reverse-engineer a localized date string.
An unfinished pick emits nothing. If a customer sets a start but no end on an optional option, no property is written — a half-formed range would put a start with no end on the order line.
Conditions
A Date Range can be used as a condition source with six comparators. The rule value is a single date, and every operator is evaluated against the whole span:
| Comparator | Evaluates as | Aug 10–15 vs Aug 12 |
|---|---|---|
| is | The range covers the date (start ≤ date ≤ end) | ✅ matches |
| is not | The range does not cover it | ❌ |
| is before | The whole range is earlier (end < date) | ❌ |
| is after | The whole range is later (start > date) | ❌ |
| is empty | Neither date has been chosen | — |
| is not empty | A start has been picked | — |
Containment is the useful reading of is: a booking of Aug 10–15 plainly includes Aug 12. For before and after, containment doesn't apply, so each takes the far edge — they read as "entirely before" and "entirely after", as in "if the rental ends before the season opens".
is / is before / is after are mutually exclusive
For any complete range, every date satisfies exactly one of the three, and no date satisfies two. That makes rule sets easy to reason about.
Edge cases:
- A same-day range behaves exactly like the single Date type
- A half-picked range (start chosen, end not yet) counts as a one-day range at the start, so conditions stay steady between the two clicks instead of flickering
- A rule value that isn't a valid date matches nothing — including
is not - Conditions re-evaluate live as the customer picks; the dependent option shows or hides without a page reload
Use Cases
Equipment hire
Label: Hire period · Count as: days Minimum duration: 1 · Maximum duration: 14 Earliest date: Days from today = 2 Labels: "Collection" / "Return"
Result: 1–14 day hires with two days' prep time
Accommodation
Label: Your stay · Count as: nights Minimum duration: 2 Available dates: All dates except… → Blocked dates for closures Labels: "Check in" / "Check out"
Result: Two-night minimum stays, with closure dates unbookable
Seasonal rental
Label: Rental period · Count as: days Available dates: Only specific dates → Available periods covering the season
Result: Bookings restricted to the open season
Delivery window
Label: Delivery window · Count as: days Available dates: All dates except… → Blocked days of the week: Saturday, Sunday Latest date: Days from today = 30
Result: Weekday-only delivery windows up to a month ahead
Best Practices
Get "Count as" right first:
- It changes the number on the order and the minimum a customer must meet
- Hire and services usually count days; stays count nights
Prefer relative windows to fixed dates:
- "Days from today" keeps working without maintenance
- A specific Latest date silently stops accepting bookings once it passes
Block closures rather than relying on customers to notice:
- Blocked days and dates grey out and can't be booked through
- Remember a range can't span a closed day — long minimums plus frequent closures can leave very few valid ranges
Name the fields for the job:
- "Check in / Check out" for stays, "Collection / Return" for hire
- The defaults are only hints; an unlabelled pair is harder to read
Use the hidden properties in your theme:
- Read
_{label} start,_{label} end, and_{label} days/nightsfor fulfilment logic - Don't parse the visible string — its format is a styling setting and can change
Troubleshooting
Every end date is greyed after I pick a start: A minimum or maximum duration, or a blocked day inside the span, leaves no legal end. The summary says so when no end exists at all
Customers can't book far enough ahead: Check Latest date — a fixed Specific date may have passed. Prefer "Days from today"
The calendar shows nothing selectable: Under Only specific dates, the allow-list may be empty or entirely in the past
No cart property appeared: The range was left half-picked. Both dates are required before anything is written
The cart shows a different date format than I expected: Format and separator are template settings — see Types Settings
A condition on a date inside the range isn't matching: Confirm you're using is. is before / is after test the whole span, not containment
Styling
Date Range has its own dedicated styling — field layout, the calendar panel, day cells and range fill, unavailable-day treatment, date format, and the selection summary are all configurable via named templates.
See Date Range Styling for the full settings reference, and Sandbox & Live Preview for how to build a test calendar while you style.
Related
- Date — a single calendar date
- Date Range Styling — the full styling reference
- Time Picker — a time of day
- Types Settings — assign a template, and set the date format and separator
- Condition Types — using a Date Range as a condition source
- Required Fields — making options required
- CSS Class & CSS ID — target this option from your theme CSS