# DateRangePicker

> Picks a start and end date from a two-month calendar, with optional preset ranges.

Category: Forms · Status: stable · Package: @bindshq/stance-react@0.1.1 · Docs: https://stanceui.com/components/date-range-picker

Use DateRangePicker for reporting periods, campaign windows and filters. The popover closes once both dates are chosen. Presets cover common ranges in one click. With startName and endName, the dates are submitted as ISO values.

## Import

```tsx
import { DateRangePicker } from '@bindshq/stance-react';
```

Styles are imported once per app: `@bindshq/stance-tokens/css` and `@bindshq/stance-react/styles.css`.

## Examples

### Basic

```tsx
import { DateRangePicker, FormField } from '@bindshq/stance-react';

const TODAY = new Date(2026, 10, 11);

export function Basic() {
  return (
    <FormField label="Campaign window" style={{ width: 300 }}>
      <DateRangePicker locale="en-GB" today={TODAY} startName="from" endName="to" />
    </FormField>
  );
}
```

### With presets

```tsx
import { DateRangePicker, FormField } from '@bindshq/stance-react';

const TODAY = new Date(2026, 10, 11);

const day = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);

const presets = [
  { label: 'Today', range: (t: Date) => ({ start: t, end: t }) },
  { label: 'Last 7 days', range: (t: Date) => ({ start: day(t, -6), end: t }) },
  { label: 'Last 30 days', range: (t: Date) => ({ start: day(t, -29), end: t }) },
  {
    label: 'This month',
    range: (t: Date) => ({
      start: new Date(t.getFullYear(), t.getMonth(), 1),
      end: new Date(t.getFullYear(), t.getMonth() + 1, 0),
    }),
  },
];

export function WithPresets() {
  return (
    <FormField label="Reporting period" style={{ width: 300 }}>
      <DateRangePicker
        locale="en-GB"
        today={TODAY}
        presets={presets}
        defaultValue={presets[1]!.range(TODAY)}
      />
    </FormField>
  );
}
```

### Controlled

```tsx
import { useState } from 'react';
import { DateRangePicker } from '@bindshq/stance-react';
import type { DateRange } from '@bindshq/stance-react';

const TODAY = new Date(2026, 10, 11);

export function Controlled() {
  const [range, setRange] = useState<DateRange>({ start: null, end: null });
  return (
    <div style={{ display: 'grid', gap: 8, width: 300 }}>
      <DateRangePicker
        aria-label="Deployment window"
        locale="en-GB"
        today={TODAY}
        min={TODAY}
        value={range}
        onValueChange={setRange}
      />
      <p style={{ margin: 0, fontSize: 13 }}>
        {range.start && range.end
          ? `${range.start.toDateString()} → ${range.end.toDateString()}`
          : 'No range chosen'}
      </p>
    </div>
  );
}
```

## API reference

| Component | Prop | Type | Default | Description |
| --- | --- | --- | --- | --- |
| DateRangePicker | `value / defaultValue` | `{ start: Date \| null; end: Date \| null }` | None | Selected range. |
| DateRangePicker | `onValueChange` | `(value: DateRange) => void` | None | Called as the range changes. |
| DateRangePicker | `presets` | `{ label: string; range: (today: Date) => DateRange }[]` | None | Shortcut ranges beside the calendar. |
| DateRangePicker | `startName / endName` | `string` | None | Hidden input names for form submission. |
| DateRangePicker | `min / max / isDateDisabled` | `Date \| null / (date) => boolean` | None | Availability rules, as in Calendar. |
| DateRangePicker | `numberOfMonths` | `1 \| 2` | `2` | Months shown. |
| DateRangePicker | `locale / weekStartsOn` | `string / 0 to 6` | None | Localisation. |
| DateRangePicker | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Trigger height. |
| DateRangePicker | `invalid` | `boolean` | None | Invalid styling and aria-invalid. |
| DateRangePicker | `labels` | `Partial<DateRangePickerLabels>` | None | placeholder, calendar, presets, clear. |

## Accessibility

- The trigger is a button named by its FormField label, showing the current range or placeholder.
- The popover is a labelled dialog; presets are a named group of toggle buttons with aria-pressed.
- Range start and end days are announced as such, and in-range days are marked selected.
- Focus returns to the trigger when the popover closes.

## Keyboard

| Keys | Action |
| --- | --- |
| `Enter` `Space` | Open the picker / choose a day or preset. |
| `Arrows` `Page Up/Down` | Navigate days (see Calendar). |
| `Esc` | Close without changing the range. |

## Guidelines

**Do**

- Offer presets for analytics views.
- Show the chosen range in the page heading or summary.

**Don’t**

- Use two separate DatePickers for one range.

## Related

- https://stanceui.com/components/calendar
- https://stanceui.com/components/date-picker
- https://stanceui.com/components/filter-bar
