# Date Picker

> A field that opens a calendar, with presets and range support.

Category: Forms. Docs: https://neonkit.heyaadi.com/components/date-picker

## Installation

```bash
npx shadcn@latest add https://neonkit.heyaadi.com/r/date-picker.json
```

With the `@neonkit` namespace configured: `npx shadcn@latest add @neonkit/date-picker`.

npm dependencies: none. Also needs `lib/utils.ts` (`cn`) and `lib/neon.ts` (`neonVars`), which the CLI adds.

Builds on: [Calendar](https://neonkit.heyaadi.com/components/calendar.md), [Icons](https://neonkit.heyaadi.com/components/icons.md), [Popover](https://neonkit.heyaadi.com/components/popover.md). The CLI installs them too.

## Usage

```tsx
import { DatePicker } from "@/components/ui/date-picker"

const [date, setDate] = React.useState<Date>()

<DatePicker label="Departure" value={date ?? null} onValueChange={setDate} />
```

## Examples

### Campaign dates

Range mode with a preset column. Two months show from the sm breakpoint up, and the panel closes once the last day is picked.

```tsx
"use client";

import * as React from "react";
import type { DateRange } from "@/components/ui/calendar";
import { DatePicker } from "@/components/ui/date-picker";

const presets = [
  { label: "Black Friday week", value: { from: new Date(2026, 10, 23), to: new Date(2026, 10, 29) } },
  { label: "Cyber Monday", value: { from: new Date(2026, 10, 30), to: new Date(2026, 10, 30) } },
  { label: "Holiday push", value: { from: new Date(2026, 11, 1), to: new Date(2026, 11, 24) } },
  { label: "Whole quarter", value: { from: new Date(2026, 9, 1), to: new Date(2026, 11, 31) } },
];

// Count on UTC day numbers so a daylight-saving change can't add or lose a day.
const daysIn = ({ from, to }: DateRange) =>
  from && to
    ? Math.round(
        (Date.UTC(to.getFullYear(), to.getMonth(), to.getDate()) -
          Date.UTC(from.getFullYear(), from.getMonth(), from.getDate())) /
          86_400_000,
      ) + 1
    : 0;

export default function DatePickerDemo() {
  const [flight, setFlight] = React.useState<DateRange | undefined>({
    from: new Date(2026, 10, 23),
    to: new Date(2026, 10, 29),
  });
  const days = flight ? daysIn(flight) : 0;

  return (
    <div className="w-full max-w-sm rounded-2xl border border-white/10 bg-white/[0.03] p-5">
      <p className="text-sm font-medium text-white/90">Winter sale campaign</p>
      <p className="mt-1 text-xs leading-5 text-white/55">Ads run from the first day at 00:00 to the last day at 23:59.</p>
      <DatePicker
        mode="range"
        label="Flight dates"
        value={flight ?? null}
        onValueChange={setFlight}
        presets={presets}
        minDate={new Date(2026, 9, 1)}
        maxDate={new Date(2026, 11, 31)}
        containerClassName="mt-4"
        description={days ? `${days} ${days === 1 ? "day" : "days"} of delivery` : "Pick when the ads should run."}
      />
    </div>
  );
}
```

### A single day in a form

formatOptions sets how the value reads, isDateDisabled blocks weekends, and name submits yyyy-mm-dd.

```tsx
"use client";

import * as React from "react";
import { Button } from "@/components/ui/button";
import { DatePicker } from "@/components/ui/date-picker";

const longDate: Intl.DateTimeFormatOptions = { weekday: "short", month: "long", day: "numeric", year: "numeric" };

export default function DatePickerSingle() {
  const [status, setStatus] = React.useState("");

  function submit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const due = new FormData(event.currentTarget).get("due");
    setStatus(due ? `Invoice due ${due}.` : "Pick a due date first.");
  }

  return (
    <form onSubmit={submit} className="grid w-full max-w-xs gap-3">
      <DatePicker
        name="due"
        label="Invoice due"
        placeholder="No due date"
        formatOptions={longDate}
        isDateDisabled={(date) => date.getDay() === 0 || date.getDay() === 6}
        description="Weekdays only. Submits as yyyy-mm-dd."
        onValueChange={() => setStatus("")}
      />
      <div className="flex items-center gap-3">
        <Button type="submit" variant="solid" size="sm">
          Save invoice
        </Button>
        <p aria-live="polite" className="text-xs text-white/55">
          {status}
        </p>
      </div>
    </form>
  );
}
```

### Relative presets

Presets are plain values, so build them from today. The one that matches the value is marked.

```tsx
"use client";

import * as React from "react";
import type { DateRange } from "@/components/ui/calendar";
import { DatePicker } from "@/components/ui/date-picker";

const daysAgo = (days: number) => {
  const today = new Date();
  return new Date(today.getFullYear(), today.getMonth(), today.getDate() - days);
};

export default function DatePickerRelativePresets() {
  const [range, setRange] = React.useState<DateRange>();
  const today = daysAgo(0);
  const presets = [
    { label: "Today", value: { from: today, to: today } },
    { label: "Yesterday", value: { from: daysAgo(1), to: daysAgo(1) } },
    { label: "Last 7 days", value: { from: daysAgo(6), to: today } },
    { label: "Last 30 days", value: { from: daysAgo(29), to: today } },
    { label: "Month to date", value: { from: new Date(today.getFullYear(), today.getMonth(), 1), to: today } },
  ];

  return (
    <DatePicker
      mode="range"
      label="Traffic"
      placeholder="All time"
      value={range ?? null}
      onValueChange={setRange}
      presets={presets}
      maxDate={today}
      containerClassName="max-w-xs"
    />
  );
}
```

### Sizes, error and disabled

```tsx
import { DatePicker } from "@/components/ui/date-picker";

export default function DatePickerStates() {
  return (
    <div className="grid w-full max-w-xs gap-5">
      <DatePicker size="sm" aria-label="Start date" defaultValue={new Date(2026, 9, 12)} />
      <DatePicker
        label="Passport expiry"
        defaultValue={new Date(2026, 11, 3)}
        error="Your passport must be valid for six months after you travel."
      />
      <DatePicker size="lg" label="Ship date" defaultValue={new Date(2026, 9, 20)} disabled description="Locked once the order ships." />
    </div>
  );
}
```

## API reference

### DatePicker

Also accepts native button attributes, and the ref points at the trigger. className and style go to the field box.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | `"single" \| "range"` | `"single"` | One day, or a first and last day. |
| `value` | `Date \| DateRange \| null` | — | Controlled value, shaped by mode. Pass null for controlled with nothing picked. |
| `defaultValue` | `Date \| DateRange` | — | Initial value when uncontrolled. |
| `onValueChange` | `(value: Date \| DateRange \| undefined) => void` | — | Called with the picked day, a complete { from, to }, or undefined when cleared. A half-picked range is never reported. |
| `presets` | `{ label: string; value: Date \| DateRange }[]` | — | Shortcuts shown in a column beside the calendar (a row on phones). |
| `placeholder` | `ReactNode` | `"Pick a date"` | Shown while nothing is picked. Range mode defaults to "Pick a date range". |
| `formatOptions` | `Intl.DateTimeFormatOptions` | `{ month: "short", day: "numeric", year: "numeric" }` | How the value reads in the field. Ranges use formatRange, so shared parts collapse: Oct 12 – 16, 2026. |
| `locale` | `string` | `"en-US"` | BCP 47 tag for the field text and the calendar. |
| `minDate` | `Date` | — | Earlier days can't be picked. |
| `maxDate` | `Date` | — | Later days can't be picked. |
| `isDateDisabled` | `(date: Date) => boolean` | — | Return true for days that can't be picked. A range can't run across one. |
| `weekStartsOn` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6` | `from locale` | First column of the calendar, 0 for Sunday. |
| `numberOfMonths` | `number` | `2 for ranges on sm+, else 1` | Months in the calendar. |
| `name` | `string` | — | Submits yyyy-mm-dd, or yyyy-mm-dd/yyyy-mm-dd for a range, with a surrounding form. A form reset puts back the starting date. |
| `required` | `boolean` | `false` | Stops an empty submit with the browser's own message and turns the field red until a date is picked. |
| `label` | `ReactNode` | — | Visible label. Names the trigger together with the value. |
| `description` | `ReactNode` | — | Helper text under the field. |
| `error` | `ReactNode` | — | Red invalid state and message. Replaces description. The calendar keeps its own color. |
| `disabled` | `boolean` | `false` | Blocks opening and leaves the value out of form data. |
| `color` | `NeonColor` | `inherited` | Palette name or hex. Carried into the popover. |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Field height: 32, 40 or 48px, matching Input. |
| `containerClassName` | `string` | — | Classes for the outer block with the label and message. |

## Accessibility

- When the browser rejects the field on submit (required, type, pattern), it turns red until it's edited or the form resets. The browser shows its own message.
- The trigger is a button with aria-haspopup="dialog" and aria-expanded, named by the label plus the current value, so a screen reader hears "Departure, Oct 14, 2026".
- Click, Enter, Space or Arrow Down opens the calendar with focus on the picked day. Escape or a click outside closes it and focus returns to the trigger.
- Inside, the calendar keeps its full keyboard grid. Tab moves between the presets, the month buttons and the active day, and tabbing past the end closes the panel.
- In range mode the panel says which end you're picking, and a polite live region announces it.
- The clear button is a separate button after the trigger, labelled "Clear date" or "Clear dates".
- Without a visible label, pass aria-label.

## Source

`components/ui/date-picker.tsx`

```tsx
"use client";

import * as React from "react";
import { CalendarDays, X } from "@/components/ui/icons";

import { Calendar, type DateRange } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { neonVars, type NeonColor } from "@/lib/neon";


// Intl pads ranges and times with thin or narrow no-break spaces, and Node and
// browsers disagree on which. Plain spaces keep server and client text identical.
const plainSpaces = (text: string) => text.replace(/[\u2009\u202f\u00a0]/g, " ");
const INVALID = "255 77 94";

const sizes = {
  sm: {
    field: "h-8 rounded-md text-xs",
    trigger: "gap-1.5 px-2.5 [&_svg]:size-3.5",
    clear: "mr-1.5 size-5 rounded-[4px] [&_svg]:size-3",
    label: "text-xs",
  },
  md: {
    field: "h-10 rounded-lg text-sm",
    trigger: "gap-2 px-3 [&_svg]:size-4",
    clear: "mr-2 size-6 rounded-md [&_svg]:size-3.5",
    label: "text-sm",
  },
  lg: {
    field: "h-12 rounded-xl text-base",
    trigger: "gap-2.5 px-4 [&_svg]:size-[18px]",
    clear: "mr-2.5 size-7 rounded-md [&_svg]:size-4",
    label: "text-sm",
  },
} as const;

const DEFAULT_FORMAT: Intl.DateTimeFormatOptions = { month: "short", day: "numeric", year: "numeric" };

const pad = (value: number) => String(value).padStart(2, "0");
const isoDay = (date: Date) => `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
const sameDay = (a?: Date, b?: Date) => (!a || !b ? a === b : isoDay(a) === isoDay(b));
const startOfMonth = (date: Date) => new Date(date.getFullYear(), date.getMonth(), 1);

const subscribeWide = (onChange: () => void) => {
  const query = window.matchMedia("(min-width: 640px)");
  query.addEventListener?.("change", onChange);
  return () => query.removeEventListener?.("change", onChange);
};

/** Two months for ranges from the sm breakpoint up; one on phones and on the server. */
function useWide() {
  return React.useSyncExternalStore(
    subscribeWide,
    () => window.matchMedia("(min-width: 640px)").matches,
    () => false,
  );
}

/**
 * True once the browser rejects the field on submit (required, type, pattern), until it's
 * edited, its value changes or the form resets. The browser still shows its own message;
 * this keeps the field red after that bubble fades.
 */
function useRejected(ref: React.RefObject<HTMLInputElement | HTMLTextAreaElement | null>, value?: string) {
  const [rejected, setRejected] = React.useState<{ value?: string } | null>(null);
  const valueRef = React.useRef(value);
  React.useEffect(() => {
    valueRef.current = value;
  });
  React.useEffect(() => {
    const element = ref.current;
    if (!element) return;
    const form = element.form;
    const flag = () => setRejected({ value: valueRef.current });
    const clear = () => setRejected(null);
    element.addEventListener("invalid", flag);
    element.addEventListener("input", clear);
    form?.addEventListener("reset", clear);
    return () => {
      element.removeEventListener("invalid", flag);
      element.removeEventListener("input", clear);
      form?.removeEventListener("reset", clear);
    };
  }, [ref]);
  return rejected !== null && rejected.value === value;
}

export interface DatePickerPreset<T> {
  label: string;
  value: T;
}

interface DatePickerBaseProps
  extends Omit<
    React.ButtonHTMLAttributes<HTMLButtonElement>,
    "color" | "value" | "defaultValue" | "onChange" | "children" | "type" | "name"
  > {
  /** Shown while nothing is picked. */
  placeholder?: React.ReactNode;
  /** How the picked date reads in the field. Ranges collapse shared parts: Oct 12 – 16, 2026. */
  formatOptions?: Intl.DateTimeFormatOptions;
  /** BCP 47 tag for the field text and the calendar. */
  locale?: string;
  minDate?: Date;
  maxDate?: Date;
  /** Return true for days that can't be picked. */
  isDateDisabled?: (date: Date) => boolean;
  /** 0 is Sunday. Defaults to the locale's first day of the week. */
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
  /** Months in the calendar. Defaults to 2 for ranges from the sm breakpoint up, else 1. */
  numberOfMonths?: number;
  /** Palette name or any hex color. Inherits `--neon-accent` when omitted. */
  color?: NeonColor;
  size?: keyof typeof sizes;
  /** Submits yyyy-mm-dd (or yyyy-mm-dd/yyyy-mm-dd for a range) under this name. */
  name?: string;
  /** Blocks form submission until a date (or a full range) is picked. */
  required?: boolean;
  label?: React.ReactNode;
  /** Helper text under the field. Hidden while `error` is set. */
  description?: React.ReactNode;
  /** Marks the field invalid and shows this message. Pass `true` for the red state alone. */
  error?: React.ReactNode;
  /** Classes for the field box. */
  className?: string;
  /** Classes for the outer block holding the label, field and message. */
  containerClassName?: string;
}

export interface DatePickerSingleProps extends DatePickerBaseProps {
  mode?: "single";
  /** Controlled value. Pass null for "controlled, nothing picked". */
  value?: Date | null;
  defaultValue?: Date;
  /** Called with the picked day, or undefined when cleared. */
  onValueChange?: (date: Date | undefined) => void;
  presets?: DatePickerPreset<Date>[];
}

export interface DatePickerRangeProps extends DatePickerBaseProps {
  mode: "range";
  value?: DateRange | null;
  defaultValue?: DateRange;
  /** Called with a complete { from, to }, or undefined when cleared. */
  onValueChange?: (range: DateRange | undefined) => void;
  presets?: DatePickerPreset<DateRange>[];
}

export type DatePickerProps = DatePickerSingleProps | DatePickerRangeProps;

type Picked = Date | DateRange | undefined;

const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
  (
    {
      mode = "single",
      value: valueProp,
      defaultValue,
      onValueChange,
      placeholder,
      presets,
      formatOptions,
      locale = "en-US",
      minDate,
      maxDate,
      isDateDisabled,
      weekStartsOn,
      numberOfMonths,
      color,
      size = "md",
      disabled,
      name,
      required = false,
      label,
      description,
      error,
      className,
      containerClassName,
      style,
      id: idProp,
      onKeyDown,
      "aria-describedby": ariaDescribedBy,
      "aria-label": ariaLabel,
      ...props
    },
    ref,
  ) => {
    const triggerRef = React.useRef<HTMLButtonElement>(null);
    React.useImperativeHandle(ref, () => triggerRef.current as HTMLButtonElement);

    const autoId = React.useId();
    const id = idProp ?? autoId;
    const labelId = `${id}-label`;
    const valueId = `${id}-value`;
    const errored = Boolean(error);
    const message = errored ? (error === true ? null : error) : description;
    const messageId = message ? `${id}-${errored ? "error" : "description"}` : undefined;
    const s = sizes[size];
    const range = mode === "range";

    const [uncontrolled, setUncontrolled] = React.useState<Picked>(defaultValue);
    const value: Picked = valueProp !== undefined ? (valueProp ?? undefined) : uncontrolled;
    const single = !range && value instanceof Date ? value : undefined;
    const span = range && value && !(value instanceof Date) && value.from ? value : undefined;
    const hasValue = Boolean(single ?? span);

    const [open, setOpen] = React.useState(false);
    // A range in progress stays here until its end is picked; closing early discards it.
    const [draft, setDraft] = React.useState<DateRange | null>(null);
    const [month, setMonth] = React.useState(() => startOfMonth(single ?? span?.from ?? new Date()));
    const wide = useWide();
    const months = numberOfMonths ?? (range && wide ? 2 : 1);

    const formatter = React.useMemo(
      () => new Intl.DateTimeFormat(locale, formatOptions ?? DEFAULT_FORMAT),
      [locale, formatOptions],
    );

    let text: React.ReactNode = placeholder ?? (range ? "Pick a date range" : "Pick a date");
    if (single) text = plainSpaces(formatter.format(single));
    else if (span?.from && span.to) text = plainSpaces(formatter.formatRange(span.from, span.to));
    else if (span?.from) text = `${plainSpaces(formatter.format(span.from))} –`;

    function setOpenState(next: boolean) {
      if (next) {
        setMonth(startOfMonth(single ?? span?.from ?? new Date()));
        setDraft(null);
      }
      setOpen(next);
    }

    function commit(next: Picked) {
      if (valueProp === undefined) setUncontrolled(next);
      (onValueChange as ((value: Picked) => void) | undefined)?.(next);
    }

    function pickPreset(preset: DatePickerPreset<Date> | DatePickerPreset<DateRange>) {
      const picked = preset.value;
      const anchor = picked instanceof Date ? picked : picked.from;
      if (anchor) setMonth(startOfMonth(anchor));
      setDraft(null);
      commit(picked);
      setOpen(false);
    }

    const isPresetActive = (preset: DatePickerPreset<Date> | DatePickerPreset<DateRange>) =>
      preset.value instanceof Date
        ? sameDay(preset.value, single)
        : !!span && sameDay(preset.value.from, span.from) && sameDay(preset.value.to, span.to);

    // A form reset goes back to the date the picker started with.
    const proxyRef = React.useRef<HTMLInputElement>(null);
    const initialValue = React.useRef(value);
    const resetRef = React.useRef<() => void>(() => {});
    React.useEffect(() => {
      resetRef.current = () => {
        const initial = initialValue.current;
        setOpen(false);
        setDraft(null);
        if (initial === value) return;
        commit(initial);
      };
    });
    React.useEffect(() => {
      const form = proxyRef.current?.form;
      if (!form) return;
      const onReset = () => resetRef.current();
      form.addEventListener("reset", onReset);
      return () => form.removeEventListener("reset", onReset);
    }, []);

    const formValue = single
      ? isoDay(single)
      : span?.from && span.to
        ? `${isoDay(span.from)}/${isoDay(span.to)}`
        : "";
    const rejected = useRejected(proxyRef, formValue);
    const invalid = errored || rejected;

    const calendarProps = {
      month,
      onMonthChange: setMonth,
      numberOfMonths: months,
      minDate,
      maxDate,
      disabled: isDateDisabled,
      weekStartsOn,
      locale,
      autoFocus: true,
    };

    return (
      <div
        style={neonVars(color)}
        className={cn("[--neon:var(--neon-accent,34_211_238)]", "grid w-full gap-1.5", containerClassName)}
      >
        {label && (
          <label
            id={labelId}
            htmlFor={id}
            onClick={(event) => {
              // Focus the trigger like a native field label, without opening the calendar.
              event.preventDefault();
              triggerRef.current?.focus();
            }}
            className={cn("w-fit font-medium text-white/80", s.label)}
          >
            {label}
            {required && (
              <span
                aria-hidden
                title="Required"
                className="relative -top-px ml-1.5 inline-block size-[5px] rounded-full bg-[rgb(var(--neon))] align-middle shadow-[0_0_4px_rgb(var(--neon)/CALC(0.9*var(--neon-glow,1))),0_0_10px_rgb(var(--neon)/CALC(0.5*var(--neon-glow,1)))]"
              />
            )}
          </label>
        )}
        <Popover open={open && !disabled} onOpenChange={setOpenState}>
          <div
            data-state={open ? "open" : "closed"}
            style={invalid ? ({ "--neon": INVALID, ...style } as React.CSSProperties) : style}
            className={cn(
              "group/field relative flex w-full items-center border border-white/10 bg-white/[0.03] text-white/90",
              "transition-[border-color,background-color,box-shadow] ease-[cubic-bezier(0.23,1,0.32,1)] duration-[150ms,150ms,320ms]",
              "focus-within:border-[rgb(var(--neon)/0.8)] focus-within:bg-[rgb(var(--neon)/0.04)] focus-within:shadow-[0_0_0_1px_rgb(var(--neon)/0.2),0_0_20px_-4px_rgb(var(--neon)/CALC(0.5*var(--neon-glow,1))),inset_0_0_12px_-2px_rgb(var(--neon)/CALC(0.14*var(--neon-glow,1)))]",
              open &&
                "border-[rgb(var(--neon)/0.8)] bg-[rgb(var(--neon)/0.04)] shadow-[0_0_0_1px_rgb(var(--neon)/0.2),0_0_20px_-4px_rgb(var(--neon)/CALC(0.5*var(--neon-glow,1))),inset_0_0_12px_-2px_rgb(var(--neon)/CALC(0.14*var(--neon-glow,1)))]",
              !disabled && !open && "hover:[&:not(:focus-within)]:border-white/20",
              invalid && "border-[rgb(var(--neon)/0.55)]",
              invalid && !open && "hover:[&:not(:focus-within)]:border-[rgb(var(--neon)/0.75)]",
              disabled && "cursor-not-allowed opacity-50",
              s.field,
              className,
            )}
          >
            <PopoverTrigger asChild>
              <button
                ref={triggerRef}
                id={id}
                type="button"
                disabled={disabled}
                // The name always ends with the visible date, so an aria-label adds to it instead of hiding it.
                aria-labelledby={label || ariaLabel ? `${labelId} ${valueId}` : undefined}
                aria-describedby={[ariaDescribedBy, messageId].filter(Boolean).join(" ") || undefined}
                onKeyDown={(event) => {
                  onKeyDown?.(event);
                  if (event.defaultPrevented || open || disabled) return;
                  if (event.key === "ArrowDown") {
                    event.preventDefault();
                    setOpenState(true);
                  }
                }}
                className={cn(
                  // The panel reads its color from here, so the red error state stays on the field.
                  "[--neon:var(--neon-accent,34_211_238)]",
                  "flex h-full min-w-0 flex-1 cursor-pointer items-center rounded-[inherit] text-left outline-none disabled:cursor-not-allowed",
                  "[&_svg]:shrink-0 [&_svg]:text-white/40 [&_svg]:transition-colors [&_svg]:duration-200",
                  invalid
                    ? "group-focus-within/field:[&_svg]:text-[#ff4d5e] group-data-[state=open]/field:[&_svg]:text-[#ff4d5e]"
                    : "group-focus-within/field:[&_svg]:text-[rgb(var(--neon)/0.9)] group-data-[state=open]/field:[&_svg]:text-[rgb(var(--neon)/0.9)]",
                  s.trigger,
                  hasValue && !disabled && "pr-1.5",
                )}
                {...props}
              >
                {!label && ariaLabel && (
                  <span id={labelId} hidden>
                    {ariaLabel}
                  </span>
                )}
                <CalendarDays aria-hidden />
                <span id={valueId} className={cn("min-w-0 flex-1 truncate tabular-nums", !hasValue && "text-white/50")}>
                  {text}
                </span>
              </button>
            </PopoverTrigger>
            {hasValue && !disabled && (
              <button
                type="button"
                aria-label={range ? "Clear dates" : "Clear date"}
                onClick={() => {
                  commit(undefined);
                  triggerRef.current?.focus();
                }}
                className={cn(
                  "grid shrink-0 cursor-pointer place-items-center text-white/40 outline-none",
                  "transition-[background-color,color] duration-150 ease-out hover:bg-white/[0.08] hover:text-white",
                  "focus-visible:text-white focus-visible:ring-2 focus-visible:ring-[rgb(var(--neon)/0.6)]",
                  s.clear,
                )}
              >
                <X aria-hidden />
              </button>
            )}
            {/* Carries the date into forms, under the field so a validation bubble points at it. */}
            <input
              ref={proxyRef}
              aria-hidden
              tabIndex={-1}
              autoComplete="off"
              name={name}
              value={formValue}
              required={required}
              disabled={disabled}
              onChange={() => {}}
              onFocus={() => triggerRef.current?.focus()}
              className="pointer-events-none absolute inset-x-0 bottom-0 h-px w-full opacity-0"
            />
          </div>
          <PopoverContent align="start" className="w-auto p-0">
            <div className="flex flex-col sm:flex-row">
              {presets && presets.length > 0 && (
                <div
                  role="group"
                  aria-label="Presets"
                  className="flex gap-1 overflow-x-auto border-b border-white/10 p-2 sm:w-40 sm:flex-col sm:overflow-visible sm:border-b-0 sm:border-r"
                >
                  {(presets as (DatePickerPreset<Date> | DatePickerPreset<DateRange>)[]).map((preset) => {
                    const active = isPresetActive(preset);
                    return (
                      <button
                        key={preset.label}
                        type="button"
                        aria-pressed={active}
                        onClick={() => pickPreset(preset)}
                        className={cn(
                          "relative shrink-0 cursor-pointer whitespace-nowrap rounded-md px-2.5 py-1.5 text-left text-[13px] outline-none",
                          "transition-[background-color,color] duration-150 ease-out",
                          "focus-visible:ring-2 focus-visible:ring-[rgb(var(--neon)/0.6)]",
                          active
                            ? "bg-[rgb(var(--neon)/0.1)] text-[rgb(var(--neon))]"
                            : "text-white/65 hover:bg-white/[0.06] hover:text-white",
                        )}
                      >
                        {active && (
                          <span
                            aria-hidden
                            className="absolute inset-y-1.5 left-0 hidden w-0.5 rounded-full bg-[rgb(var(--neon))] shadow-[0_0_8px_rgb(var(--neon)/var(--neon-glow,1))] sm:block"
                          />
                        )}
                        {preset.label}
                      </button>
                    );
                  })}
                </div>
              )}
              <div>
                {range ? (
                  <Calendar
                    mode="range"
                    selected={draft ?? span ?? null}
                    onSelect={(next) => {
                      if (next.from && next.to) {
                        setDraft(null);
                        commit(next);
                        setOpen(false);
                      } else setDraft(next);
                    }}
                    {...calendarProps}
                  />
                ) : (
                  <Calendar
                    selected={single ?? null}
                    onSelect={(next) => {
                      commit(next);
                      setOpen(false);
                    }}
                    {...calendarProps}
                  />
                )}
                {range && (
                  <p aria-live="polite" className="border-t border-white/10 px-4 py-2.5 text-xs text-white/55">
                    {draft?.from ? (
                      <>
                        Starts <span className="text-white/90">{plainSpaces(formatter.format(draft.from))}</span>. Pick the last day.
                      </>
                    ) : (
                      "Pick the first day, then the last."
                    )}
                  </p>
                )}
              </div>
            </div>
          </PopoverContent>
        </Popover>
        {message && (
          <p id={messageId} className={cn("text-xs leading-5", errored ? "text-[#ff4d5e]" : "text-white/55")}>
            {message}
          </p>
        )}
      </div>
    );
  },
);
DatePicker.displayName = "DatePicker";

export { DatePicker };
```
