SGUI / Development
DateRangeSelector
Inline range drafting, named preset descriptions, Apply and Cancel transactions.
Loading examples…
Loading examples…
Examples
Loading examples…
Component documentation
SGUI / Development
Inline range drafting, named preset descriptions, Apply and Cancel transactions.
Loading examples…
Loading examples…
Loading examples…
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2026-10-12 – 2026-10-16
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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2026-10-12 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { DateRangeSelector, type DateRange } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DateRangeSelectorPlaygroundExample() {
const [range, setRange] = useState<DateRange | null>({"start":"2026-10-12","end":"2026-10-16"});
const [activeEndpoint,setActiveEndpoint]=useState<"start"|"end">("end");
const [cancels, setCancels] = useState(0);
return (
<>
<ThemeScope density="comfortable">
<Stack align="start" gap={3}>
<DateRangeSelector label={"Course schedule"} disabled={false} readOnly={false} 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} onCancel={() => setCancels(count => count + 1)} />
</Stack>
</ThemeScope>
</>
);
}
Compare segment, calendar and action target spacing in an independent scope.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2026-10-12 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { DateRangeSelector, type DateRange } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DateRangeSelectorCompactExample() {
const [range, setRange] = useState<DateRange | null>({"start":"2026-10-12","end":"2026-10-16"});
const [activeEndpoint,setActiveEndpoint]=useState<"start"|"end">("end");
const [cancels, setCancels] = useState(0);
return (
<>
<ThemeScope density="compact">
<Stack align="start" gap={3}>
<DateRangeSelector label={"Course schedule"} disabled={false} readOnly={false} 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} onCancel={() => setCancels(count => count + 1)} />
</Stack>
</ThemeScope>
</>
);
}
Compare segment, calendar and action target spacing in an independent scope.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2026-10-12 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import { DateRangeSelector, type DateRange } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DateRangeSelectorComfortableExample() {
const [range, setRange] = useState<DateRange | null>({"start":"2026-10-12","end":"2026-10-16"});
const [activeEndpoint,setActiveEndpoint]=useState<"start"|"end">("end");
const [cancels, setCancels] = useState(0);
return (
<>
<ThemeScope density="comfortable">
<Stack align="start" gap={3}>
<DateRangeSelector label={"Course schedule"} disabled={false} readOnly={false} 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} onCancel={() => setCancels(count => count + 1)} />
</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 { DateRangeSelector, type DateRange, Button } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DateRangeSelectorFormExample() {
const [range, setRange] = useState<DateRange | null>({"start":"2026-10-12","end":"2026-10-16"});
const [activeEndpoint,setActiveEndpoint]=useState<"start"|"end">("end");
const [cancels, setCancels] = useState(0);
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}>
<DateRangeSelector label={"Course schedule"} disabled={false} readOnly={false} 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} onCancel={() => setCancels(count => count + 1)} />
</Stack>
<Button type="submit">Submit schedule locally</Button>
<Typography role="status">Submitted {submits} times. Host owns persistence.</Typography>
</Stack>
</form>
</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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 1 | 2 | 3 | 4 | 5 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
29 | 30 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 1 | 2 |
2026-10-12 – 2026-12-10
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,type DateRange} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function ThreeMonthDateRangeSelectorExample() {
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%'}}>
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 1 | 2 | 3 | 4 | 5 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function DateRangeSelectorPeriodNavigationExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 1 | 2 | 3 | 4 | 5 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function DateRangeSelectorPeriodNavigationExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="comfortable">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 1 | 2 | 3 | 4 | 5 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,type DateRange} from '@structured-growth/sg-ui/experimental';
export default function DateRangeSelectorPeriodNavigationExample() {
const [range,setRange]=useState<DateRange|null>({"start":"2026-10-07","end":"2026-10-16"});
return (
<>
<ThemeScope density="compact">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 1 | 2 | 3 | 4 | 5 | 6 |
2026-10-12 – 2026-10-18
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,getRelativeDateRange,type DateRange,type DateRangePreset} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RangePresetsInlineExample() {
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%, 48rem)"}}>
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-08
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 1 | 2 | 3 | 4 | 5 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 1 | 2 | 3 | 4 | 5 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
29 | 30 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 1 | 2 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 31 | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | 1 | 2 | 3 | 4 | 5 | 6 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
31 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 1 | 2 | 3 | 4 | 5 | 6 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
28 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 1 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
25 | 26 | 27 | 28 | 29 | 30 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 1 | 2 | 3 | 4 | 5 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 1 | 2 | 3 | 4 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
29 | 30 | 31 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 1 | 2 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-07 – 2026-10-16
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,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">
<DateRangeSelector 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>
</>
);
}
This repeatable example pins the host reference date to October 16, 2026. Try today, a week from today, two weeks from today, in a month or a week ago. Next/last weekdays are strictly after/before the reference; next month/year preserves the day and clamps at month end. A real host supplies today's civil date in its chosen timezone and pins it for the editing session. Committed values are absolute dates and do not drift.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
2026-10-16 – 2026-10-23
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,type DateRange} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RelativeDateRangeSelectorExample() {
// 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)'}}>
<DateRangeSelector label="Relative travel dates" showFields entryMode="text" referenceDate={referenceDate} months={1} value={range} onValueChange={setRange}/>
</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.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 1 | 2 | 3 | 4 | 5 | 6 |
2026-10-12 – 2026-10-18
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,getRelativeDateRange,type DateRange,type DateRangePreset} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RangePresetsInlineExample() {
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%, 48rem)"}}>
<DateRangeSelector label="Reporting period" showFields entryMode="text" months={2} presetPlacement="side" presets={presets} firstDayOfWeek="mon" value={range} onValueChange={setRange} name="reporting" />
</Box>
</ThemeScope>
</>
);
}
Both locale examples start with the same ISO civil range, October 12–16, 2026. Locale controls calendar formatting and direction; it does not shift those dates. This host reports in America/Chicago; converting a local time to an instant is a separate host decision. The sample adapter retains English fallback UI messages; production hosts supply their translations.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| Mo | Di | Mi | Do | Fr | Sa | So |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2026-10-12 – 2026-10-16
'use client';
import { useState } from 'react';
import { Provider } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,type DateRange} from '@structured-growth/sg-ui/experimental';
import {SGTranslationProvider,formatIcuMessage} from '@structured-growth/sg-ui/i18n';
export default function GermanCivilRangeExample() {
const [value,setValue]=useState<DateRange|null>({"start":"2026-10-12","end":"2026-10-16"});
return (
<>
<SGTranslationProvider value={{locale:"de-DE",t:(_key,options)=>formatIcuMessage(options.defaultMessage,"de-DE",options.values),useNamespace:()=>{}}}>
<Provider>
<DateRangeSelector label="Reporting dates" value={value} onValueChange={setValue} defaultFocusedDate="2026-10-12" months={1} name="reporting" />
</Provider>
</SGTranslationProvider>
</>
);
}
Both locale examples start with the same ISO civil range, October 12–16, 2026. Locale controls calendar formatting and direction; it does not shift those dates. This host reports in America/Chicago; converting a local time to an instant is a separate host decision. The sample adapter retains English fallback UI messages; production hosts supply their translations.
Shift and Left or Right moves the range when enabled. Alt and Left or Right resizes the end; add Shift to resize the start when enabled. Escape cancels dragging. Drag the first or last day to resize, or an interior day to move. Shift and drag moves from any selected day. At duration limits the opposite boundary follows; fixed duration moves the whole range.
| السبت | الأحد | الاثنين | الثلاثاء | الأربعاء | الخميس | الجمعة |
|---|---|---|---|---|---|---|
٢٦ | ٢٧ | ٢٨ | ٢٩ | ٣٠ | ١ | ٢ |
٣ | ٤ | ٥ | ٦ | ٧ | ٨ | ٩ |
١٠ | ١١ | ١٢ | ١٣ | ١٤ | ١٥ | ١٦ |
١٧ | ١٨ | ١٩ | ٢٠ | ٢١ | ٢٢ | ٢٣ |
٢٤ | ٢٥ | ٢٦ | ٢٧ | ٢٨ | ٢٩ | ٣٠ |
٣١ | ١ | ٢ | ٣ | ٤ | ٥ | ٦ |
2026-10-12 – 2026-10-16
'use client';
import { useState } from 'react';
import { Provider } from '@structured-growth/sg-ui/theme';
import {DateRangeSelector,type DateRange} from '@structured-growth/sg-ui/experimental';
import {SGTranslationProvider,formatIcuMessage} from '@structured-growth/sg-ui/i18n';
export default function ArabicCivilRangeExample() {
const [value,setValue]=useState<DateRange|null>({"start":"2026-10-12","end":"2026-10-16"});
return (
<>
<SGTranslationProvider value={{locale:"ar-EG",t:(_key,options)=>formatIcuMessage(options.defaultMessage,"ar-EG",options.values),useNamespace:()=>{}}}>
<Provider>
<DateRangeSelector label="Reporting dates" value={value} onValueChange={setValue} defaultFocusedDate="2026-10-12" months={1} name="reporting" />
</Provider>
</SGTranslationProvider>
</>
);
}