Date range
Pick a start and end date on one calendar. React:
DateTimeRange. Vanilla:
createDateTimeRangePicker. Web Component:
<datetime-picker-range>.
Value shape
-
asStringomitted or false:{ start: Date | null; end: Date | null } -
asString={true}:{ start: string | null; end: string | null }
Controlled usage passes the same shape to value. Incomplete
ranges may have one side still null while the user
finishes the second click.
Behavior
- First click sets start. Second click sets end and commits.
- No OK button. Commit happens when the range is complete.
- Hover preview highlights the tentative span.
- Keyboard grid navigation works like the single-date calendar.
-
Non-inline
defaultOpendefaults to true. UsedefaultOpen={false}or controlledopenfor a closed trigger pattern.
Limitations
Range is date-only and intentionally smaller than
DateTime:
- No
popover - No
anchorEl - No
themeprop (use CSS /data-ctp-theme) - No
modeorlayout - No
use12HoursorshowSeconds
Still supported: bounds, disable past/future, weekStartsOn,
locale, labels, format,
asString, open-state props, inline,
className, style.
React example
import { useState } from "react";
import { DateTimeRange } from "universal-datetime-picker";
import "universal-datetime-picker/style.css";
type Range = { start: Date | null; end: Date | null };
export function StayDates() {
const [range, setRange] = useState<Range>({ start: null, end: null });
return (
<DateTimeRange
inline
asString={false}
value={range}
onChange={setRange}
disablePastDates
weekStartsOn={1}
/>
);
} Vanilla example
import { createDateTimeRangePicker } from "universal-datetime-picker/vanilla";
import "universal-datetime-picker/style.css";
const mount = document.querySelector("#range");
if (!mount) throw new Error("#range missing");
createDateTimeRangePicker(mount, {
inline: true,
asString: false,
disablePastDates: true,
onChange: (value) => console.log(value.start, value.end),
}); Closed-by-default overlay trigger
Range overlays are centered (no popover). Keep them closed until a button opens them:
import { useState } from "react";
import { DateTimeRange } from "universal-datetime-picker";
import "universal-datetime-picker/style.css";
export function RangeModal() {
const [open, setOpen] = useState(false);
const [range, setRange] = useState({ start: null, end: null });
return (
<>
<button type="button" onClick={() => setOpen(true)}>
Select dates
</button>
<DateTimeRange
open={open}
onOpenChange={setOpen}
asString={false}
value={range}
onChange={setRange}
/>
</>
);
}
Uncontrolled alternative: defaultOpen={false}
plus a way to call into open state if your wrapper exposes it. Controlled
open is the clearest pattern.
Components · Props · Overlay · Examples · Troubleshooting