# DateRangeFilter

> A date-range chip for filter rows: presets plus a two-month range calendar.

Category: Forms. Docs page: https://rime.mjsons.net/components/date-range-filter

## Installation

```bash
npx shadcn@latest add KezLahd/rime/date-range-filter
```

DateRangeFilter is the date filter in a FilterBar. It reads as a chip like Select's, with presets (last 7 days, this month) and a range calendar.

## Usage

```tsx
import { DateRangeFilter } from "@/components/ui";

<DateRangeFilter aria-label="Issued" value={range} onChange={setRange} />
```

## Props: DateRangeFilter

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` (required) | `DateRange` |  | Both null = no filter. A half-picked range never reaches onChange. |
| `onChange` (required) | `(value: DateRange) => void` |  |  |
| `presets` | `ReadonlyArray<DateRangePreset>` | `DEFAULT_DATE_RANGE_PRESETS` |  |
| `min` | `IsoDate` |  |  |
| `max` | `IsoDate` |  |  |
| `isDateDisabled` | `(date: IsoDate) => boolean` |  |  |
| `placeholder` | `string` | `"All dates"` | Shown when no range is set. |
| `appearance` | `"chip" \| "field"` | `"chip"` | chip = 32px filter-bar chip. field = form-control height, beside Select. |
| `months` | `1 \| 2` |  | Calendars side by side. Defaults to 2, or 1 under 640px. |
| `disabled` | `boolean` |  |  |
| `invalid` | `boolean` |  |  |
| `id` | `string` |  |  |
| `aria-label` | `string` |  | Names the control. The current range is appended, so it is read too. |
| `className` | `string` |  |  |
| `inline` | `boolean` | `false` | Show the panel open, in place under the trigger: no portal, no focus move, no outside-click listener. For docs and thumbnails. |

## Examples

### Open

inline shows the presets and calendars open under the chip, in place.

```tsx
<DateRangeFilter inline aria-label="Issued" value={range} onChange={setRange} />
```

### Chip

```tsx
<DateRangeFilter value={range} onChange={setRange} aria-label="Date" />
```

## Theme tokens

Per-component tokens. Undeclared by default: the default below is the fallback the CSS uses. Set any of them at :root or on a wrapper to restyle every instance.

| Token | Default |
| --- | --- |
| `--chip-height` | `var(--control-h-sm)` |
| `--chip-radius` | `var(--r-sm)` |
| `--field-focus-border` | `rgba(var(--rgb-brand), 0.7)` |
| `--field-focus-ring` | `var(--focus-halo)` |
| `--field-focus-ring-invalid` | `0 0 0 4px rgba(var(--rgb-danger), 0.14)` |

System tokens it reads: `--brand-deep`, `--chip-active-fill`, `--chip-active-fill-hover`, `--chip-active-shadow`, `--control-h-sm`, `--danger-base`, `--density`, `--dur`, `--dur-fast`, `--ease`, `--ease-out`, `--focus-color`, `--focus-gap`, `--focus-halo`, `--focus-ring`, `--font-body`, `--ink-body`, `--ink-brand`, `--ink-disabled`, `--ink-muted`, `--line`, `--line-brand`, `--line-soft`, `--r-2xs`, `--r-lg`, `--r-md`, `--r-sm`, `--r-xs`, `--recess-fill`, `--recess-fill-hover`, `--rgb-brand`, `--rgb-brand-deep`, `--rgb-contact`, `--rgb-danger`, `--rgb-white`, `--shadow-menu`, `--shadow-recess`, `--surface-solid`, `--text-caption`, `--text-input`, `--text-small`, `--wash-active`, `--wash-row`, `--wash-strong`, `--wash-subtle`, `--z-popover`.

## Accessibility

- The clear button is a separate control, so the trigger never nests a button.

## Do

- Put it after the Select chips in a FilterBar.

## Don't

- Don't use it for a single date; that is DateField.
