bearnie

Calendar

A date picker calendar with keyboard navigation, range selection, and form integration.

Installation

npx bearnie add calendar
npx bearnie add calendar

Usage

import { Calendar } from "@/components/bearnie/calendar"
<Calendar defaultValue="2026-09-15" name="date" />

Clicking a day selects it (clicking again deselects). With a name, a hidden input carries the ISO date so the calendar works inside plain HTML forms. Navigate with the arrow keys, jump months with PageUp/PageDown, and select with Enter or Space.

Examples

Range selection

mode="range" selects a from/to pair: the first click sets the start, the second sets the end, and a third starts over.

Two months side by side

months={2} shows linked months next to each other (stacked on small screens) — the booking-site layout for picking a stay.

Range picker with presets

The calendar listens for a calendar-set CustomEvent, so preset buttons (“Last 7 days”, “Month to date”…) can drive the selection from outside. Compose it with a sidebar and a footer for the full analytics-style range picker.

Min and max

Days outside the bounds are disabled, and month navigation stops at the edges.

Date picker

Compose with Popover for a date picker. Listen for calendar-change to update the trigger label.

Week starts on Sunday

Props

Prop Type Default Description
mode “single” | “range” “single” Select one date or a from/to pair
months number 1 Months shown side by side (stacked on small screens)
defaultValue string - Preselected date, ISO format YYYY-MM-DD (single mode)
defaultFrom / defaultTo string - Preselected range bounds, ISO format (range mode)
min / max string - Earliest/latest selectable date, ISO format
weekStartsOn 0 | 1 1 First day of the week (0 = Sunday, 1 = Monday)
name string - Form field name — renders hidden inputs (name, or name-from/name-to in range mode)
class string - Additional CSS classes

Events

The calendar dispatches a bubbling calendar-change CustomEvent on every selection: detail is { date } in single mode and { from, to } in range mode, all ISO strings (or null).

It also listens for a calendar-set CustomEvent to set the selection programmatically — dispatch it on the calendar element with detail: { date } (single mode) or detail: { from, to } (range mode). The view jumps to show the new selection and a calendar-change event fires in response.

Accessibility

  • The grid uses role="grid" with labelled gridcell buttons and aria-selected on chosen days.
  • Roving tabindex: Tab enters the grid once, ArrowLeft/Right/Up/Down move by day and week, PageUp/PageDown by month, Home/End to the start/end of the week, Enter/Space selects.
  • Month and weekday names come from the visitor’s locale, and the month label announces changes via aria-live.