Forms
Date range picker
A date-range field: one trigger showing "start – end", a popover hosting `Calendar` in range mode.
Import
import { DateRangePicker } from '@the_viveksingh/vivek-ui'A stay
One trigger reading start – end, a popup hosting Calendar in range mode. It closes on the second date and returns focus to the field; Escape after a first click restores the last complete range instead of leaving one date of two in the form.
3 nights — the form receives stay-start and stay-end as ISO dates.
const [stay, setStay] = useState({ start: null, end: null })
<Field label="Stay">
<DateRangePicker name="stay" value={stay} onValueChange={setStay} />
</Field>
// The form receives two ISO fields: stay-start and stay-end.
// The trigger's accessible name reads the range in words:
// "Stay: March 12, 2026 to March 15, 2026".Bounded, weekends refused
min, max and disabledDates pass straight through to Calendar, where a disabled day is unreachable by keyboard rather than merely unclickable.
Only March 2026, and never a weekend — the calendar refuses those days rather than accepting and rejecting later.
<DateRangePicker
min={new Date(2026, 2, 1)}
max={new Date(2026, 2, 31)}
disabledDates={(d) => d.getDay() === 0 || d.getDay() === 6}
name="workshop"
/>Props
Generated from the package's own type declarations, so this table cannot drift from the code.
| Prop | Type | Default | Description |
|---|---|---|---|
value | DateRange | null | — | Controlled range. `end` is `null` while the user has picked only a start. |
defaultValue | DateRange | null | — | — |
onValueChange | (value: DateRange | null) => void | — | Fires on every change, including the half-selected `{ start, end: null }` step, so a consumer can react to the first click. Read `end !== null` for "complete". |
min | Date | null | — | — |
max | Date | null | — | — |
disabledDates | DisabledDates | — | — |
weekStartsOn | WeekStart | — | — |
locale | DateLocale | — | — |
size | 'sm' | 'md' | 'lg' | — | — |
disabled | boolean | — | — |
invalid | boolean | — | Sets `aria-invalid` on the trigger. Injected by `Field`. |
required | boolean | — | Injected by `Field`. |
name | string | — | Submits two hidden fields, `{name}-start` and `{name}-end`, as ISO dates — the same convention `Calendar` uses in range mode, so a form does not care which rendered it. |
placeholder | { start?: string; end?: string; } | — | Shown in place of a missing start or end. Default `'Start date'` / `'End date'`. |
format | (date: Date) => string | — | Renders a date as the trigger's text. Default `YYYY-MM-DD`, which is deterministic — `Intl` output differs between Node builds and browsers, so a locale-aware default would hydrate differently for two of your users. |
label | string | — | The control's name, spoken before the current range: "Stay: 12 Mar 2026 to 15 Mar 2026". Default `'Date range'`. Prefer `aria-labelledby` (via rest) when a visible label exists. |
open | boolean | — | Controlled popup state. |
defaultOpen | boolean | — | — |
onOpenChange | (open: boolean) => void | — | — |
side | Side | — | — |
align | Align | — | — |
offset | number | — | — |
padding | number | — | — |
container | PortalContainer | — | Where the popup portals. Defaults to `document.body`. |
Every remaining prop is spread onto the root element, so all standard HTML and ARIA attributes work. className and style are merged with the library's own, never replaced, and the ref forwards to the root DOM node.
Rendering
DateRangePicker declares 'use client' because it needs state, effects or event handlers. Importing it into a Server Component creates a client boundary at this component — everything above it stays on the server.