SGUI / Development
DateRangePicker
An input component for selecting a range of dates.
Loading examples…
Loading examples…
Examples
Loading examples…
Component documentation
SGUI / Development
An input component for selecting a range of dates.
Loading examples…
Loading examples…
Loading examples…
Explore ISO values, field states and host-owned availability. The selected example theme also applies to picker portals.
Limits are inclusive and relative to today in your browser’s timezone, pinned when this example opens. Crossing a limit moves the other boundary to the same date.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { DateRangePicker, type DateRange } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DateRangePickerPlaygroundExample() {
const [range, setRange] = useState<DateRange | null>({"start":"2026-10-12","end":"2026-10-16"});
const [activeEndpoint,setActiveEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="comfortable">
<Stack align="start" gap={3}>
<DateRangePicker label={"Course schedule"} disabled={false} readOnly={false} fieldMode="text" presentation="popover" description={"Select the calendar icon or type a date range, such as 'next week'"} invalid={false} errorMessage="Please review this schedule." unavailable={[]} descriptionPlacement="above" errorPlacement="below" rangeClickBehavior="adjust-nearest" nearestEndpointTieBreak="end" rangeDragBehavior="move-and-resize" calendarNavigation="independent" calendarLayout="paged" scrollMonths={12} showFields={false} showActions={true} commitBehavior="apply" activeEndpoint={activeEndpoint} onActiveEndpointChange={setActiveEndpoint} navigation="period" allowMonthSelection={true} allowYearSelection={true} periodPickerProps={{"yearNavigation":"scroll","yearEntry":"select","yearsPerPage":12}} showTitle={false} entryMode="text" referenceDate="2026-10-16" presetPlacement="side" required={false} presets={[]} months={1} firstDayOfWeek="mon" defaultFocusedDate="2026-10-14" name="schedule" value={range} onValueChange={setRange} />
</Stack>
</ThemeScope>
</>
);
}
Compare segment, calendar and action target spacing in an independent scope.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { DateRangePicker, type DateRange } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DateRangePickerCompactExample() {
const [range, setRange] = useState<DateRange | null>({"start":"2026-10-12","end":"2026-10-16"});
const [activeEndpoint,setActiveEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="compact">
<Stack align="start" gap={3}>
<DateRangePicker label={"Course schedule"} disabled={false} readOnly={false} fieldMode="text" presentation="popover" description={"Select the calendar icon or type a date range, such as 'next week'"} invalid={false} errorMessage="Please review this schedule." unavailable={[]} descriptionPlacement="above" errorPlacement="below" rangeClickBehavior="adjust-nearest" nearestEndpointTieBreak="end" rangeDragBehavior="move-and-resize" calendarNavigation="independent" calendarLayout="paged" scrollMonths={12} showFields={false} showActions={true} commitBehavior="apply" activeEndpoint={activeEndpoint} onActiveEndpointChange={setActiveEndpoint} navigation="period" allowMonthSelection={true} allowYearSelection={true} periodPickerProps={{"yearNavigation":"scroll","yearEntry":"select","yearsPerPage":12}} showTitle={false} entryMode="text" referenceDate="2026-10-16" presetPlacement="side" required={false} presets={[]} months={1} firstDayOfWeek="mon" defaultFocusedDate="2026-10-14" name="schedule" value={range} onValueChange={setRange} />
</Stack>
</ThemeScope>
</>
);
}
Compare segment, calendar and action target spacing in an independent scope.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { DateRangePicker, type DateRange } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DateRangePickerComfortableExample() {
const [range, setRange] = useState<DateRange | null>({"start":"2026-10-12","end":"2026-10-16"});
const [activeEndpoint,setActiveEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="comfortable">
<Stack align="start" gap={3}>
<DateRangePicker label={"Course schedule"} disabled={false} readOnly={false} fieldMode="text" presentation="popover" description={"Select the calendar icon or type a date range, such as 'next week'"} invalid={false} errorMessage="Please review this schedule." unavailable={[]} descriptionPlacement="above" errorPlacement="below" rangeClickBehavior="adjust-nearest" nearestEndpointTieBreak="end" rangeDragBehavior="move-and-resize" calendarNavigation="independent" calendarLayout="paged" scrollMonths={12} showFields={false} showActions={true} commitBehavior="apply" activeEndpoint={activeEndpoint} onActiveEndpointChange={setActiveEndpoint} navigation="period" allowMonthSelection={true} allowYearSelection={true} periodPickerProps={{"yearNavigation":"scroll","yearEntry":"select","yearsPerPage":12}} showTitle={false} entryMode="text" referenceDate="2026-10-16" presetPlacement="side" required={false} presets={[]} months={1} firstDayOfWeek="mon" defaultFocusedDate="2026-10-14" name="schedule" value={range} onValueChange={setRange} />
</Stack>
</ThemeScope>
</>
);
}
Native fields serialize local values. Hosts own persistence, timezone and availability policy.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { DateRangePicker, type DateRange, Button } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DateRangePickerFormExample() {
const [range, setRange] = useState<DateRange | null>({"start":"2026-10-12","end":"2026-10-16"});
const [activeEndpoint,setActiveEndpoint]=useState<"start"|"end">("end");
const [submits, setSubmits] = useState(0);
return (
<>
<ThemeScope density="comfortable">
<form onSubmit={event => { event.preventDefault(); setSubmits(count => count + 1); }}>
<Stack align="start" gap={3}>
<Stack align="start" gap={3}>
<DateRangePicker label={"Course schedule"} disabled={false} readOnly={false} fieldMode="text" presentation="popover" description={"Select the calendar icon or type a date range, such as 'next week'"} invalid={false} errorMessage="Please review this schedule." unavailable={[]} descriptionPlacement="above" errorPlacement="below" rangeClickBehavior="adjust-nearest" nearestEndpointTieBreak="end" rangeDragBehavior="move-and-resize" calendarNavigation="independent" calendarLayout="paged" scrollMonths={12} showFields={false} showActions={true} commitBehavior="apply" activeEndpoint={activeEndpoint} onActiveEndpointChange={setActiveEndpoint} navigation="period" allowMonthSelection={true} allowYearSelection={true} periodPickerProps={{"yearNavigation":"scroll","yearEntry":"select","yearsPerPage":12}} showTitle={false} entryMode="text" referenceDate="2026-10-16" presetPlacement="side" required={true} presets={[]} months={1} firstDayOfWeek="mon" defaultFocusedDate="2026-10-14" name="schedule" value={range} onValueChange={setRange} />
</Stack>
<Button type="submit">Submit schedule locally</Button>
<Typography role="status">Submitted {submits} times. Host owns persistence.</Typography>
</Stack>
</form>
</ThemeScope>
</>
);
}
Try 1/1/2026 - 1/3/26, today - a week from today, or last week, then press Enter or leave the field. Last week is the complete Monday–Sunday week before the fixed October 16, 2026 reference: October 5–11. This/last/next month and year select complete periods too. Change dates in the calendar and Apply, or Cancel to keep the accepted range. A production host supplies today's civil reference date; accepted dates remain absolute.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function EditableDateRangeExample() {
const referenceDate='2026-10-16';
const [range,setRange]=useState<DateRange|null>({"start":"2026-01-01","end":"2026-01-03"});
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 24rem)'}}>
<DateRangePicker showFields label="Reporting period" referenceDate={referenceDate} firstDayOfWeek="mon" entryMode="text" months={1} value={range} onValueChange={setRange}/>
</Box>
</ThemeScope>
</>
);
}
The field-shaped trigger shows the committed range. Selected dates join into continuous weekly bands with rounded row ends. Initial selection completes in either direction. Once a range is complete, calendar clicks adjust the end by default; a click on or before the start restarts selection. This example enables optional freehand start/end textboxes above the calendar (hidden by default); type either endpoint or select an inclusive range. Apply commits and Cancel discards. The dropdown shifts within the viewport before it needs to scroll. Two months sit alongside each other when space permits and stack on narrow hosts. Formats normalize on blur or Enter; invalid, reversed or unavailable ranges cannot Apply.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RangeDropdown1Example() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-12","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 20rem)'}}>
<DateRangePicker label="Travel dates" showFields entryMode="text" months={1} value={range} onValueChange={setRange} defaultFocusedDate="2026-10-12" name="travel" />
</Box>
</ThemeScope>
</>
);
}
The field-shaped trigger shows the committed range. Selected dates join into continuous weekly bands with rounded row ends. Initial selection completes in either direction. Once a range is complete, calendar clicks adjust the end by default; a click on or before the start restarts selection. This example enables optional freehand start/end textboxes above the calendar (hidden by default); type either endpoint or select an inclusive range. Apply commits and Cancel discards. The dropdown shifts within the viewport before it needs to scroll. Two months sit alongside each other when space permits and stack on narrow hosts. Formats normalize on blur or Enter; invalid, reversed or unavailable ranges cannot Apply.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RangeDropdown2Example() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-12","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 20rem)'}}>
<DateRangePicker label="Travel dates" showFields entryMode="text" months={2} value={range} onValueChange={setRange} defaultFocusedDate="2026-10-12" name="travel" />
</Box>
</ThemeScope>
</>
);
}
Fixed and relative choices share one extensible list of selectable labels. This demo resolves full periods against October 16, 2026, with Monday-start weeks. The custom business-week option belongs to the host and can be omitted. A choice updates the draft; Apply commits and Cancel discards. Presets can precede or follow the calendars; visual and keyboard order match as panels wrap on narrow screens.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,getRelativeDateRange,type DateRange,type DateRangePreset} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RangePresets1Example() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-12","end":"2026-10-18"});
// Resolve periods from the host's civil date, not the browser clock.
const referenceDate = '2026-10-16';
const lastWeek = getRelativeDateRange(referenceDate,{unit:'week',offset:-1,weekStartsOn:1});
// Example host policy: Monday-Friday, with no holiday-calendar adjustment.
const friday = new Date(lastWeek.start+'T00:00:00Z');
friday.setUTCDate(friday.getUTCDate()+4);
const presets:DateRangePreset[] = [
{id:'fixed',label:'Autumn launch',value:{start:'2026-09-01',end:'2026-09-30'}},
{id:'week',label:'This week',value:getRelativeDateRange(referenceDate,{unit:'week',weekStartsOn:1})},
{id:'month',label:'This month',value:getRelativeDateRange(referenceDate,{unit:'month'})},
{id:'year',label:'This year',value:getRelativeDateRange(referenceDate,{unit:'year'})},
{id:'last-year',label:'Last year',value:getRelativeDateRange(referenceDate,{unit:'year',offset:-1})},
{id:'business',label:'Last business week',description:'Custom host rule: Monday-Friday; holidays are not adjusted.',value:{start:lastWeek.start,end:friday.toISOString().slice(0,10)}},
];
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:"min(100%, 20rem)"}}>
<DateRangePicker label="Reporting period" entryMode="text" months={1} presetPlacement="side" presets={presets} firstDayOfWeek="mon" value={range} onValueChange={setRange} name="reporting" />
</Box>
</ThemeScope>
</>
);
}
Fixed and relative choices share one extensible list of selectable labels. This example explicitly enables the optional freehand endpoint textboxes. This demo resolves full periods against October 16, 2026, with Monday-start weeks. The custom business-week option belongs to the host and can be omitted. A choice updates the draft; Apply commits and Cancel discards. Presets can precede or follow the calendars; visual and keyboard order match as panels wrap on narrow screens.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,getRelativeDateRange,type DateRange,type DateRangePreset} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RangePresets2Example() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-12","end":"2026-10-18"});
// Resolve periods from the host's civil date, not the browser clock.
const referenceDate = '2026-10-16';
const lastWeek = getRelativeDateRange(referenceDate,{unit:'week',offset:-1,weekStartsOn:1});
// Example host policy: Monday-Friday, with no holiday-calendar adjustment.
const friday = new Date(lastWeek.start+'T00:00:00Z');
friday.setUTCDate(friday.getUTCDate()+4);
const presets:DateRangePreset[] = [
{id:'fixed',label:'Autumn launch',value:{start:'2026-09-01',end:'2026-09-30'}},
{id:'week',label:'This week',value:getRelativeDateRange(referenceDate,{unit:'week',weekStartsOn:1})},
{id:'month',label:'This month',value:getRelativeDateRange(referenceDate,{unit:'month'})},
{id:'year',label:'This year',value:getRelativeDateRange(referenceDate,{unit:'year'})},
{id:'last-year',label:'Last year',value:getRelativeDateRange(referenceDate,{unit:'year',offset:-1})},
{id:'business',label:'Last business week',description:'Custom host rule: Monday-Friday; holidays are not adjusted.',value:{start:lastWeek.start,end:friday.toISOString().slice(0,10)}},
];
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:"min(100%, 20rem)"}}>
<DateRangePicker label="Reporting period" showFields entryMode="text" months={2} presetPlacement="side" presets={presets} firstDayOfWeek="mon" value={range} onValueChange={setRange} name="reporting" />
</Box>
</ThemeScope>
</>
);
}
Three initially consecutive months share one selection. Month/year choices and arrows navigate only the calendar used; set calendarNavigation to linked to move all views together. Each month keeps its minimum width; months wrap in narrow hosts. The picker uses the same selector inside its dropdown.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function ThreeMonthDateRangePickerExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-12","end":"2026-12-10"});
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'100%'}}>
<DateRangePicker label="Reporting period" months={3} entryMode="text" value={range} onValueChange={setRange} />
</Box>
</ThemeScope>
</>
);
}
Separate month and year choices navigate without changing the range. Independent From/To calendars retain endpoint-aware availability.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function DateRangePickerPeriodNavigationExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangePicker label="Travel dates" min="2026-01-01" max="2027-12-31" months={2} defaultFocusedDate="2026-10-07" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Separate month and year choices navigate without changing the range. Independent From/To calendars retain endpoint-aware availability.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function DateRangePickerPeriodNavigationExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="comfortable">
<DateRangePicker label="Travel dates" min="2026-01-01" max="2027-12-31" months={2} defaultFocusedDate="2026-10-07" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Separate month and year choices navigate without changing the range. Independent From/To calendars retain endpoint-aware availability.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function DateRangePickerPeriodNavigationExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangePicker label="Travel dates" min="2026-01-01" max="2027-12-31" months={2} defaultFocusedDate="2026-10-07" calendarNavigation="independent" calendarEndpoints={["start","end"]} getDateUnavailableReason={(date,context)=>context.endpoint==="start"&&date.startsWith("2027")?"No arrivals in 2027.":undefined} value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Fixed and relative choices share one extensible list of selectable labels. This example explicitly enables the optional freehand endpoint textboxes. This demo resolves full periods against October 16, 2026, with Monday-start weeks. The custom business-week option belongs to the host and can be omitted. A choice updates the draft; Apply commits and Cancel discards. Presets can precede or follow the calendars; visual and keyboard order match as panels wrap on narrow screens.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,getRelativeDateRange,type DateRange,type DateRangePreset} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RangePresets2Example() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-12","end":"2026-10-18"});
// Resolve periods from the host's civil date, not the browser clock.
const referenceDate = '2026-10-16';
const lastWeek = getRelativeDateRange(referenceDate,{unit:'week',offset:-1,weekStartsOn:1});
// Example host policy: Monday-Friday, with no holiday-calendar adjustment.
const friday = new Date(lastWeek.start+'T00:00:00Z');
friday.setUTCDate(friday.getUTCDate()+4);
const presets:DateRangePreset[] = [
{id:'fixed',label:'Autumn launch',value:{start:'2026-09-01',end:'2026-09-30'}},
{id:'week',label:'This week',value:getRelativeDateRange(referenceDate,{unit:'week',weekStartsOn:1})},
{id:'month',label:'This month',value:getRelativeDateRange(referenceDate,{unit:'month'})},
{id:'year',label:'This year',value:getRelativeDateRange(referenceDate,{unit:'year'})},
{id:'last-year',label:'Last year',value:getRelativeDateRange(referenceDate,{unit:'year',offset:-1})},
{id:'business',label:'Last business week',description:'Custom host rule: Monday-Friday; holidays are not adjusted.',value:{start:lastWeek.start,end:friday.toISOString().slice(0,10)}},
];
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:"min(100%, 20rem)"}}>
<DateRangePicker label="Reporting period" showFields entryMode="text" months={2} presetPlacement="end" presets={presets} firstDayOfWeek="mon" value={range} onValueChange={setRange} name="reporting" />
</Box>
</ThemeScope>
</>
);
}
With 7th–16th selected, any calendar click starts a new incomplete range. The next click completes it in either direction. Apply commits; Cancel discards. Clear then click 5th and 1st to create 1st–5th in every mode.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function RangeSelectionBehaviorExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangePicker label="Example range" showFields months={1} entryMode="text" rangeClickBehavior="restart" defaultFocusedDate="2026-10-07" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
With 7th–16th selected, click 13th for 7th–13th or 20th for 7th–20th. Click on or before 7th to restart; the next click completes in either direction. Apply commits; Cancel discards. Clear then click 5th and 1st to create 1st–5th in every mode.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function RangeSelectionBehaviorExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangePicker label="Example range" showFields months={1} entryMode="text" rangeClickBehavior="adjust-end" defaultFocusedDate="2026-10-07" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
With 7th–16th selected, click 5th for 5th–16th or 13th for 13th–16th. Click on or after 16th to restart; the next click completes in either direction. Apply commits; Cancel discards. Clear then click 5th and 1st to create 1st–5th in every mode.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function RangeSelectionBehaviorExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangePicker label="Example range" showFields months={1} entryMode="text" rangeClickBehavior="adjust-start" defaultFocusedDate="2026-10-07" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
With 7th–16th selected, click 5th for 5th–16th, 13th for 7th–13th or 20th for 7th–20th. Clicking 7th makes a one-day range. Calendar clicks preserve a complete range until Clear; manual fields remain independently editable. Apply commits; Cancel discards. Clear then click 5th and 1st to create 1st–5th in every mode.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function RangeSelectionBehaviorExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangePicker label="Example range" showFields months={1} entryMode="text" rangeClickBehavior="adjust-boundaries" defaultFocusedDate="2026-10-07" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Default: each click edits the closer endpoint, measured in calendar days. Outside clicks extend the nearest boundary. Equal distances edit the end by default; nearestEndpointTieBreak="start" edits the start instead. Clicking an existing endpoint leaves the range unchanged. Fixed length, whole-period selection and assigned calendar endpoints take precedence. Apply commits; Cancel discards. Clear then click 5th and 1st to create 1st–5th in every mode.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function RangeSelectionBehaviorExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangePicker label="Example range" showFields months={1} entryMode="text" rangeClickBehavior="adjust-nearest" defaultFocusedDate="2026-10-07" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
This required example hides the endpoint fields. Use Adjust dates to choose an operation, then click a target day in the existing calendar or step one day at a time, without dragging or opening another popup. Drag the first or last day itself to resize; drag an interior day to move the trip. Shift-drag any selected day to move, including a two-day trip. Keep trip length locks the current inclusive duration, so dragging either end moves the whole trip. Minimum/maximum lengths push the opposite boundary once reached. Shift+arrows moves; Alt+arrows edits the end; Alt+Shift+arrows edits the start. Escape cancels.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function AdvancedRangeExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-08"});
const [endpoint,setEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="compact">
<DateRangePicker required label="Travel interval" months={1} entryMode="text" defaultFocusedDate="2026-10-07" rangeDragBehavior="move-and-resize" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Each panel owns its range and draft. Apply commits unless immediate selection is explicitly enabled.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,getDateRangeLength,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function AdvancedRangeExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
const [endpoint,setEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="compact">
<DateRangePicker showFields label="Travel interval" months={1} entryMode="text" defaultFocusedDate="2026-10-07" rangeDragBehavior="move-and-resize" rangeLength={{mode:"fixed",value:range ? getDateRangeLength(range) : 10,unit:"days"}} value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
The first calendar edits the start date; the second edits the end date. Each navigates independently. Crossing the opposite endpoint clears that opposite date; choose it again before applying.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function AdvancedRangeExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
const [endpoint,setEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="compact">
<DateRangePicker showFields label="Travel interval" months={2} entryMode="text" defaultFocusedDate="2026-10-07" rangeDragBehavior="move-and-resize" calendarNavigation="independent" calendarEndpoints={["start","end"]} value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Each panel owns its range and draft. Apply commits unless immediate selection is explicitly enabled.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function AdvancedRangeExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
const [endpoint,setEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="compact">
<DateRangePicker showFields label="Travel interval" months={1} entryMode="text" defaultFocusedDate="2026-10-07" rangeDragBehavior="move-and-resize" calendarLayout="scroll" scrollMonths={12} value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Each panel owns its range and draft. Apply commits unless immediate selection is explicitly enabled.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function AdvancedRangeExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
const [endpoint,setEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="compact">
<DateRangePicker showFields label="Travel interval" months={1} entryMode="text" defaultFocusedDate="2026-10-07" rangeDragBehavior="move-and-resize" rangeClickBehavior="active-endpoint" activeEndpoint={endpoint} onActiveEndpointChange={setEndpoint} value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Each panel owns its range and draft. Apply commits unless immediate selection is explicitly enabled.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function AdvancedRangeExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
const [endpoint,setEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="compact">
<DateRangePicker showFields label="Travel interval" months={1} entryMode="text" defaultFocusedDate="2026-10-07" rangeDragBehavior="move-and-resize" commitBehavior="immediate" value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
Choose Start date: the 13th is unavailable for arrival. Choose End date: departure on the 13th is allowed. The host callback owns this rule.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function AdvancedRangeExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
const [endpoint,setEndpoint]=useState<"start"|"end">("end");
return (
<>
<ThemeScope density="compact">
<DateRangePicker showFields label="Travel interval" months={1} entryMode="text" defaultFocusedDate="2026-10-07" rangeDragBehavior="move-and-resize" rangeClickBehavior="active-endpoint" activeEndpoint={endpoint} onActiveEndpointChange={setEndpoint} getDateUnavailableReason={(date,context)=>context.endpoint === "start" && date.endsWith("-13") ? "Arrivals are unavailable on the 13th." : undefined} value={range} onValueChange={setRange}/>
</ThemeScope>
</>
);
}
The main range textbox accepts this/last/next week, month or year as complete periods. Open the calendar to try today, a week from today or two weeks from today in its separate endpoint fields. This example pins the host reference date to October 16, 2026; a real host supplies its own civil today and pins it for the editing session. Accepted dates do not drift.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangePicker,type DateRange} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RelativeDateRangePickerExample() {
// Host-owned civil date. Keep the same anchor for this editing session.
const referenceDate='2026-10-16';
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-16","end":"2026-10-23"});
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 22rem)'}}>
<DateRangePicker label="Relative travel dates" showFields entryMode="text" referenceDate={referenceDate} months={1} value={range} onValueChange={setRange}/>
</Box>
</ThemeScope>
</>
);
}