SGUI / Development
DatePicker
Flexible date text entry and a scoped calendar popup with clear and availability handling.
Loading examples…
Loading examples…
Examples
Loading examples…
Component documentation
SGUI / Development
Flexible date text entry and a scoped calendar popup with clear and availability handling.
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 { DatePicker } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DatePickerPlaygroundExample() {
const [value, setValue] = useState<string | null>("2026-10-14");
return (
<>
<ThemeScope density="comfortable">
<Stack align="start" gap={3}>
<DatePicker presentation="popover" label={"Course schedule"} disabled={false} readOnly={false} referenceDate="2026-10-16" description={"Local value supplied by your host."} descriptionPlacement="above" errorPlacement="below" required={false} invalid={false} errorMessage="Please review this schedule." unavailable={[]} navigation="period" allowMonthSelection={true} allowYearSelection={true} periodPickerProps={{"yearNavigation":"scroll","yearEntry":"select","yearsPerPage":12}} kind="date" hourCycle={24} showTitle={false} entryMode="text" value={value} onValueChange={setValue} defaultFocusedDate="2026-10-14" name="schedule" />
</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 { DatePicker } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DatePickerCompactExample() {
const [value, setValue] = useState<string | null>("2026-10-14");
return (
<>
<ThemeScope density="compact">
<Stack align="start" gap={3}>
<DatePicker presentation="popover" label={"Course schedule"} disabled={false} readOnly={false} referenceDate="2026-10-16" description={"Local value supplied by your host."} descriptionPlacement="above" errorPlacement="below" required={false} invalid={false} errorMessage="Please review this schedule." unavailable={[]} navigation="period" allowMonthSelection={true} allowYearSelection={true} periodPickerProps={{"yearNavigation":"scroll","yearEntry":"select","yearsPerPage":12}} kind="date" hourCycle={24} showTitle={false} entryMode="text" value={value} onValueChange={setValue} defaultFocusedDate="2026-10-14" name="schedule" />
</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 { DatePicker } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DatePickerComfortableExample() {
const [value, setValue] = useState<string | null>("2026-10-14");
return (
<>
<ThemeScope density="comfortable">
<Stack align="start" gap={3}>
<DatePicker presentation="popover" label={"Course schedule"} disabled={false} readOnly={false} referenceDate="2026-10-16" description={"Local value supplied by your host."} descriptionPlacement="above" errorPlacement="below" required={false} invalid={false} errorMessage="Please review this schedule." unavailable={[]} navigation="period" allowMonthSelection={true} allowYearSelection={true} periodPickerProps={{"yearNavigation":"scroll","yearEntry":"select","yearsPerPage":12}} kind="date" hourCycle={24} showTitle={false} entryMode="text" value={value} onValueChange={setValue} defaultFocusedDate="2026-10-14" name="schedule" />
</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 { DatePicker, Button } from '@structured-growth/sg-ui/experimental';
import { Stack, Typography } from '@structured-growth/sg-ui/primitives';
export default function DatePickerFormExample() {
const [value, setValue] = useState<string | null>("2026-10-14");
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}>
<DatePicker presentation="popover" label={"Course schedule"} disabled={false} readOnly={false} referenceDate="2026-10-16" description={"Local value supplied by your host."} descriptionPlacement="above" errorPlacement="below" required={true} invalid={false} errorMessage="Please review this schedule." unavailable={[]} navigation="period" allowMonthSelection={true} allowYearSelection={true} periodPickerProps={{"yearNavigation":"scroll","yearEntry":"select","yearsPerPage":12}} kind="date" hourCycle={24} showTitle={false} entryMode="text" value={value} onValueChange={setValue} defaultFocusedDate="2026-10-14" name="schedule" />
</Stack>
<Button type="submit">Submit schedule locally</Button>
<Typography role="status">Submitted {submits} times. Host owns persistence.</Typography>
</Stack>
</form>
</ThemeScope>
</>
);
}
Click the month or year text button for its own inline choices. Selecting a choice immediately returns to days, without action buttons. The popup keeps its dimensions. The date bounds limit years to 2026–2027 even though the optional year bounds are wider. December is unavailable; partially available months remain usable. Choosing a period changes the view; select a day to change the field.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker} from '@structured-growth/sg-ui/experimental';
export default function DatePickerPeriodNavigationExample() {
const [date,setDate]=useState<string|null>("2026-10-14");
return (
<>
<ThemeScope density="compact">
<DatePicker label="Appointment" min="2026-09-10" max="2027-02-20" periodPickerProps={{yearEntry:'select',minYear:2020,maxYear:2030}} getDateUnavailableReason={date=>date.startsWith('2026-12')?'Closed in December.':undefined} value={date} onValueChange={setDate}/>
</ThemeScope>
</>
);
}
Click the month or year text button for its own inline choices. Selecting a choice immediately returns to days, without action buttons. The popup keeps its dimensions. The date bounds limit years to 2026–2027 even though the optional year bounds are wider. December is unavailable; partially available months remain usable. Choosing a period changes the view; select a day to change the field.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker} from '@structured-growth/sg-ui/experimental';
export default function DatePickerPeriodNavigationExample() {
const [date,setDate]=useState<string|null>("2026-10-14");
return (
<>
<ThemeScope density="comfortable">
<DatePicker label="Appointment" min="2026-09-10" max="2027-02-20" periodPickerProps={{yearEntry:'select',minYear:2020,maxYear:2030}} getDateUnavailableReason={date=>date.startsWith('2026-12')?'Closed in December.':undefined} value={date} onValueChange={setDate}/>
</ThemeScope>
</>
);
}
'use client';
import { useState } from 'react';
import {DatePicker} from '@structured-growth/sg-ui/experimental';
export default function BoundedEventExample() {
const [date,setDate]=useState<string|null>(null);
return (
<>
<DatePicker label="Event date" min="2026-10-19" max="2026-10-25" defaultFocusedDate="2026-10-19" allowMonthSelection={false} allowYearSelection={false} value={date} onValueChange={setDate}/>
</>
);
}
One host availability rule covers direct entry and the calendar. An unavailable draft remains editable, blocks native submission and keeps the accepted value. Change the host rule to allow the date. This form saves locally; persistence belongs to the host.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker,Checkbox,Button} from '@structured-growth/sg-ui/experimental';
import {Box,Stack,Typography} from '@structured-growth/sg-ui/primitives';
export default function AvailabilitytextExample() {
const [value,setValue]=useState<string|null>("2026-10-14");
const [allowBlockedDate,setAllowBlockedDate]=useState(false);
const [message,setMessage]=useState("");
const reasonForDate=(date:string)=>!allowBlockedDate&&date==='2026-10-16'?'No appointment capacity':undefined;
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'100%'}}>
<form aria-label="Booking form" onSubmit={event=>{event.preventDefault();setMessage('Appointment saved locally.');}}>
<Stack gap={3}>
<Checkbox label="Accept bookings on October 16" checked={allowBlockedDate} onCheckedChange={setAllowBlockedDate}/>
<DatePicker label="Booking date" name="booking" entryMode="text" kind="date" hourCycle={24} value={value} onValueChange={date=>{setValue(date);setMessage('');}} getDateUnavailableReason={reasonForDate} defaultFocusedDate="2026-10-14" required/>
<Button type="submit">Save appointment</Button>
{message && <Typography role="status">{message}</Typography>}
</Stack>
</form>
</Box>
</ThemeScope>
</>
);
}
One host availability rule covers direct entry and the calendar. An unavailable draft remains editable, blocks native submission and keeps the accepted value. Change the host rule to allow the date. This form saves locally; persistence belongs to the host.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker,Checkbox,Button} from '@structured-growth/sg-ui/experimental';
import {Box,Stack,Typography} from '@structured-growth/sg-ui/primitives';
export default function AvailabilitysegmentsExample() {
const [value,setValue]=useState<string|null>("2026-10-14");
const [allowBlockedDate,setAllowBlockedDate]=useState(false);
const [message,setMessage]=useState("");
const reasonForDate=(date:string)=>!allowBlockedDate&&date==='2026-10-16'?'No appointment capacity':undefined;
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'100%'}}>
<form aria-label="Booking form" onSubmit={event=>{event.preventDefault();setMessage('Appointment saved locally.');}}>
<Stack gap={3}>
<Checkbox label="Accept bookings on October 16" checked={allowBlockedDate} onCheckedChange={setAllowBlockedDate}/>
<DatePicker label="Booking date" name="booking" entryMode="segments" kind="date" hourCycle={24} value={value} onValueChange={date=>{setValue(date);setMessage('');}} getDateUnavailableReason={reasonForDate} defaultFocusedDate="2026-10-14" required/>
<Button type="submit">Save appointment</Button>
{message && <Typography role="status">{message}</Typography>}
</Stack>
</form>
</Box>
</ThemeScope>
</>
);
}
One host availability rule covers direct entry and the calendar. An unavailable draft remains editable, blocks native submission and keeps the accepted value. Change the host rule to allow the date. This form saves locally; persistence belongs to the host.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker,Checkbox,Button} from '@structured-growth/sg-ui/experimental';
import {Box,Stack,Typography} from '@structured-growth/sg-ui/primitives';
export default function AvailabilitydatetimeExample() {
const [value,setValue]=useState<string|null>("2026-10-14T08:00:00");
const [allowBlockedDate,setAllowBlockedDate]=useState(false);
const [message,setMessage]=useState("");
const reasonForDate=(date:string)=>!allowBlockedDate&&date==='2026-10-16'?'No appointment capacity':undefined;
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'100%'}}>
<form aria-label="Booking form" onSubmit={event=>{event.preventDefault();setMessage('Appointment saved locally.');}}>
<Stack gap={3}>
<Checkbox label="Accept bookings on October 16" checked={allowBlockedDate} onCheckedChange={setAllowBlockedDate}/>
<DatePicker label="Booking date" name="booking" entryMode="segments" kind="datetime" hourCycle={24} value={value} onValueChange={date=>{setValue(date);setMessage('');}} getDateUnavailableReason={reasonForDate} defaultFocusedDate="2026-10-14" required/>
<Button type="submit">Save appointment</Button>
{message && <Typography role="status">{message}</Typography>}
</Stack>
</form>
</Box>
</ThemeScope>
</>
);
}
Enter ISO dates, locale-ordered slash/dot dates, or a written month (for example Oct 14, 2026). Two-digit years expand within 1950–2049 (1/1/26 becomes January 1, 2026). Relative phrases such as today and in 2 weeks use the fixed host reference date 2026-10-16. Blur or Enter normalizes valid entry. Use the calendar button to choose a date instead. Impossible dates remain invalid; ambiguous numeric order follows the active locale.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function CalendarDropdownExample() {
const [date,setDate]=useState<string|null>("2026-10-14");
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 20rem)'}}>
<DatePicker label="Appointment date" entryMode="text" referenceDate="2026-10-16" value={date} onValueChange={setDate} defaultFocusedDate="2026-10-14" name="appointment" />
</Box>
</ThemeScope>
</>
);
}
Type a known birthday directly or open the optional calendar and jump by year and month. Navigation changes the view; choosing a day commits. This fixed demo permits 1900 through October 16, 2026; hosts choose their actual policy.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function BirthdayPickerExample() {
const [date,setDate]=useState<string|null>(null);
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 22rem)'}}>
<DatePicker label="Select your birthday" entryMode="text" navigation="period" periodPickerProps={{yearsPerPage:24}} min="1900-01-01" max="2026-10-16" defaultFocusedDate="2000-01-01" name="birthday" description="For example, May 21, 1984. The host supplies the allowed dates." value={date} onValueChange={setDate}/>
</Box>
</ThemeScope>
</>
);
}
For memorable dates, direct entry avoids navigating a calendar. Leave the birthday empty initially; valid input normalizes on blur or Enter.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DateField} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function BirthdayFieldExample() {
const [date,setDate]=useState<string|null>(null);
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 22rem)'}}>
<DateField label="Select your birthday" entryMode="text" min="1900-01-01" max="2026-10-16" name="birthday" description="For example, May 21, 1984. The host supplies the allowed dates." value={date} onValueChange={setDate}/>
</Box>
</ThemeScope>
</>
);
}
Edit date and time directly, or open the calendar and type a time such as 8a or use its clock dropdown. Apply commits both together; Cancel discards popup edits. The value is a local datetime without a timezone. The host resolves it to an instant and handles daylight-saving gaps or overlaps.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function DateTimePicker24Example() {
const [value,setValue]=useState<string|null>("2026-10-14T09:30:00");
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 28rem)'}}>
<DatePicker label="Appointment date and time" kind="datetime" hourCycle={24} navigation="period" min="2026-10-01T08:00:00" max="2026-10-31T18:00:00" name="appointment" description="Local appointment time in the host's chosen timezone." value={value} onValueChange={setValue}/>
</Box>
</ThemeScope>
</>
);
}
Edit date and time directly, or open the calendar and type a time such as 8a or use its clock dropdown. Apply commits both together; Cancel discards popup edits. The value is a local datetime without a timezone. The host resolves it to an instant and handles daylight-saving gaps or overlaps.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function DateTimePicker12Example() {
const [value,setValue]=useState<string|null>("2026-10-14T09:30:00");
return (
<>
<ThemeScope density="comfortable">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 28rem)'}}>
<DatePicker label="Appointment date and time" kind="datetime" hourCycle={12} navigation="period" min="2026-10-01T08:00:00" max="2026-10-31T18:00:00" name="appointment" description="Local appointment time in the host's chosen timezone." value={value} onValueChange={setValue}/>
</Box>
</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.
'use client';
import { useState } from 'react';
import { ThemeScope } from '@structured-growth/sg-ui/theme';
import {DatePicker} from '@structured-growth/sg-ui/experimental';
import {Box} from '@structured-growth/sg-ui/primitives';
export default function RelativeDatePickerExample() {
// Host-owned civil date. Keep the same anchor for this editing session.
const referenceDate='2026-10-16';
const [date,setDate]=useState<string|null>("2026-10-16");
return (
<>
<ThemeScope density="compact">
<Box style={{inlineSize:'fit-content',maxInlineSize:'min(100%, 22rem)'}}>
<DatePicker label="Relative appointment date" entryMode="text" referenceDate={referenceDate} value={date} onValueChange={setDate}/>
</Box>
</ThemeScope>
</>
);
}