Skip to content

Date Picker

A date selection calendar supporting single, multiple, and range selection modes.

Source Code

Areia's DatePicker uses date-fns for month generation and renders a vanilla Tailwind calendar. Use DatePicker when you want an interactive Ilha island; it updates its own calendar UI and emits date-picker events.

import ilha from "ilha";
import { DatePicker } from "areia";

export default ilha.render(() => (
  <DatePicker
    mode="single"
    selected={new Date(2026, 4, 21)}
    defaultMonth={new Date(2026, 4, 1)}
  />
));

Import

import { DatePicker, type DateRange } from "areia";

Usage

DatePicker supports three selection modes: single, multiple, and range.

July 2026
S
M
T
W
T
F
S
import ilha from "ilha";
import { DatePicker } from "areia";

export default ilha.render(() => <DatePicker mode="single" />);

Call DatePicker(...) for interactive behavior. It dispatches date-picker:change when selection changes and date-picker:month-change when users navigate months.

Use DatePicker.Static(...) for static markup or when you want to initialize/wire behavior yourself. For most application usage, call DatePicker(...).

Examples

Single Date Selection

Select a single date. This is the most common use case for date pickers.

import ilha from "ilha";
import { DatePicker } from "areia";

export default ilha.render(() => (
  <div class="flex flex-col gap-3">
    <DatePicker
      mode="single"
      selected={new Date(2026, 4, 21)}
      defaultMonth={new Date(2026, 4, 1)}
    />
    <p class="text-sm text-areia-subtle">
      Selected: May 21, 2026
    </p>
  </div>
));

Multiple Date Selection

Select multiple individual dates. Use maxSelected to limit the number of selections.

import ilha from "ilha";
import { DatePicker } from "areia";

export default ilha.render(() => (
  <div class="flex flex-col gap-3">
    <DatePicker
      mode="multiple"
      selected={[
        new Date(2026, 4, 7),
        new Date(2026, 4, 14),
        new Date(2026, 4, 21),
      ]}
      defaultMonth={new Date(2026, 4, 1)}
      maxSelected={5}
    />
    <p class="text-sm text-areia-subtle">
      Select up to 5 dates.
    </p>
  </div>
));

Date Range Selection

Select a continuous date range. Range selection works well with numberOfMonths: 2 for a side-by-side view.

import ilha from "ilha";
import { DatePicker, type DateRange } from "areia";

const range: DateRange = {
  from: new Date(2026, 4, 12),
  to: new Date(2026, 4, 18),
};

export default ilha.render(() => (
  <DatePicker
    mode="range"
    selected={range}
    defaultMonth={new Date(2026, 4, 1)}
    numberOfMonths={2}
  />
));

Min and Max Dates

Use min and max to disable dates before or after an allowed range.

import ilha from "ilha";
import { DatePicker } from "areia";

export default ilha.render(() => (
  <div class="flex flex-col gap-3">
    <DatePicker
      mode="single"
      defaultMonth={new Date(2026, 4, 1)}
      min={new Date(2026, 4, 5)}
      max={new Date(2026, 4, 25)}
    />
    <p class="text-sm text-areia-subtle">
      Only dates from May 5–25 are selectable.
    </p>
  </div>
));

Disabled Dates

Use disabled to make specific dates unavailable.

import ilha from "ilha";
import { DatePicker } from "areia";

export default ilha.render(() => (
  <DatePicker
    mode="multiple"
    defaultMonth={new Date(2026, 4, 1)}
    disabled={[
      new Date(2026, 4, 5),
      new Date(2026, 4, 12),
      new Date(2026, 4, 18),
      new Date(2026, 4, 25),
    ]}
    maxSelected={5}
  />
));

Custom Week Start

Use weekStartsOn to choose the first day of the week. 0 is Sunday and 1 is Monday.

import ilha from "ilha";
import { DatePicker } from "areia";

export default ilha.render(() => (
  <DatePicker
    mode="single"
    defaultMonth={new Date(2026, 4, 1)}
    weekStartsOn={1}
  />
));

Without Outside Days

Set showOutsideDays: false to hide adjacent-month dates in the calendar grid.

import ilha from "ilha";
import { DatePicker } from "areia";

export default ilha.render(() => (
  <DatePicker
    mode="single"
    defaultMonth={new Date(2026, 4, 1)}
    showOutsideDays={false}
  />
));

With Popover

Compose with Popover to create a dropdown date picker.

import ilha from "ilha";
import { Calendar } from "lucide";
import { Button, DatePicker, Icon, Popover } from "areia";

export default ilha.render(() => (
  <Popover
    trigger={
      <Button icon={<Icon icon={Calendar} />}>
        Pick a date
      </Button>
    }
    content={
      <DatePicker
        mode="single"
        defaultMonth={new Date(2026, 4, 1)}
      />
    }
    contentClass="p-0"
  />
));

Range with Popover

Render two months inside a popover for a compact date-range picker.

import ilha from "ilha";
import { Calendar } from "lucide";
import {
  Button,
  DatePicker,
  Icon,
  Popover,
  type DateRange,
} from "areia";

const range: DateRange = {
  from: new Date(2026, 4, 12),
  to: new Date(2026, 4, 18),
};

export default ilha.render(() => (
  <Popover
    trigger={
      <Button icon={<Icon icon={Calendar} />}>
        May 12 – May 18
      </Button>
    }
    content={
      <DatePicker
        mode="range"
        selected={range}
        defaultMonth={new Date(2026, 4, 1)}
        numberOfMonths={2}
      />
    }
    contentClass="p-0"
  />
));

Listening for Changes

DatePicker emits bubbling custom events so you can integrate it with application state.

const picker = document.querySelector(
  '[data-slot="date-picker"]',
);

picker?.addEventListener("date-picker:change", (event) => {
  const { selected } = (event as CustomEvent).detail;
  console.log(selected);
});

picker?.addEventListener(
  "date-picker:month-change",
  (event) => {
    const { month } = (event as CustomEvent).detail;
    console.log(month);
  },
);

API Reference

DatePicker

Extends native div attributes.

PropTypeDefaultDescription
mode"single" | "multiple" | "range""single"Selection mode.
selectedDate | Date[] | DateRange | undefined-Selected date, dates, or range depending on mode.
monthDate-Controlled first visible month.
defaultMonthDate-Initial month when uncontrolled.
numberOfMonthsnumber1Number of consecutive months to render.
weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 60First day of the week.
showOutsideDaysbooleantrueShows adjacent-month days to fill the calendar grid.
minDate-Disables dates before this date.
maxDate-Disables dates after this date.
disabledDate[] | ((date: Date) => boolean)-Dates that cannot be selected.
maxSelectednumber-Maximum number of selected dates in multiple mode.
onChange(selected: DatePickerSelected) => void-Called by DatePicker when selection changes.
onMonthChange(month: Date) => void-Called by DatePicker when month navigation changes.
classstring-Additional CSS classes merged with the generated classes.
classNamestring-Alias for class.

DatePicker

DatePicker is an Ilha island. It renders the same calendar markup as DatePicker(...), then wires click handlers for month navigation and date selection.

It emits:

EventDetailDescription
date-picker:change{ selected }Fired after a date selection changes.
date-picker:month-change{ month: Date }Fired after month navigation.

DateRange

import type { DateRange } from "areia";

const range: DateRange = {
  from: new Date(2026, 4, 12),
  to: new Date(2026, 4, 18),
};

Design Guidelines

Choosing a Mode

  • single: Birthdays, deadlines, appointments, and one-off dates.
  • multiple: Selecting non-contiguous dates like available days or exception dates.
  • range: Travel, reports, billing periods, and other continuous spans.

Popover Composition

  • Use a popover for compact forms where the calendar should not always be visible.
  • Use two months for range selection when horizontal space allows.
  • Keep trigger labels clear, such as “Pick a date” or the formatted selected range.

Accessibility

  • Calendar days are rendered as buttons and are keyboard focusable.
  • Selected days use aria-pressed="true".
  • Disabled days use the native disabled attribute.
  • Provide surrounding form labels or descriptive text when the picker is part of a larger form.