1. Documentation
  2. Forms
  3. Calendar
ReadmenpmGitHub
  • Introduction
  • Installation
  • Theming
  • Icons
  • Accordion
  • Card
  • Scroll Area
  • Separator
  • Sidebar
  • Field
  • Label
  • Input
  • Textarea
  • Number Field
  • OTP Field
  • Select
  • Combobox
  • Checkbox
  • Radio
  • Switch
  • Slider
  • Toggle
  • Calendar
  • Date Picker
  • File Upload
  • Button
  • Copy Button
  • Dropdown
  • Command
  • Tabs
  • Breadcrumb
  • Pagination
  • Tree
  • Table
  • Data Table
  • Stat
  • Timeline
  • Avatar
  • Status Bar
  • Badge
  • Meter
  • Empty
  • Skeleton
  • Spinner
  • Toast
  • Dialog
  • Sheet
  • Popover
  • Tooltip
  • Text
  • Kbd
  • Code Block
  • Utilities
  • Design rules

Calendar

A month grid with no date library behind it — single dates or ranges, one or two months.

Loading documentation…

Toggle< PreviousDate PickerNext >

Powered by heyo

On this page

UsageRangesBounds and blackoutsLocale and week startHelpersPropertiesDateRange
October 2026
MoTuWeThFrSaSu
<Calendar value={date} onSelect={setDate} />

Calendar is the month grid. It is deliberately dependency-free: Intl.DateTimeFormat already knows every locale's month and weekday names, and the only arithmetic a calendar needs is "add a day", which Date does correctly across DST. A date library for this would cost more than the component.

Everything works on local midnight — storing a time component is how a calendar ends up off by one for anyone east of Greenwich after 23:00.

Usage

tsx
import { Calendar } from "@heyo-sh/heyo-ui";const [date, setDate] = useState<Date | null>(null);<Calendar value={date} onSelect={setDate} />;

Calendar is controlled: it owns the month you are looking at, you own the selection.

Ranges

mode="range" selects two dates and fills everything between them. The value is { from, to }, with to staying null until the second click.

October 2026November 2026
MoTuWeThFrSaSu
MoTuWeThFrSaSu
<Calendarmode="range"months={2}value={range}onSelect={setRange}/>

Bounds and blackouts

min and max set the window; disabledDate adds any rule on top of it — weekends, holidays, days already booked.

October 2026
MoTuWeThFrSaSu
<Calendarvalue={date}onSelect={setDate}min={new Date()}disabledDate={(day) => day.getDay() === 0 || day.getDay() === 6}/>

Locale and week start

locale drives the month and weekday names through Intl; weekStartsOn is 1 (Monday) by default, because most of the world starts there.

tsx
<Calendar locale="pl-PL" weekStartsOn={1} value={date} onSelect={setDate} />
A field, not a grid?

DatePicker is this calendar inside a popover, with a control that reads the date back.

Helpers

Both are exported because a calendar's caller always ends up needing them.

tsx
import { isSameDay, startOfDay } from "@heyo-sh/heyo-ui";startOfDay(new Date()); // local midnightisSameDay(a, b); // same calendar day, ignoring time

Properties

mode"single" | "range"optional

It defaults to single.

valueDate | null | DateRangeoptional

The selection. { from, to } in range mode.

onSelect(value) => voidoptional

Fires with the new selection. Selecting the same day again clears it.

months1 | 2optional

How many months side by side. It defaults to 1.

defaultMonthDateoptional

The month shown on first render. It defaults to the selection, or today.

min / maxDateoptional

Nothing before min or after max is selectable.

disabledDate(date: Date) => booleanoptional

An extra rule on top of min and max.

weekStartsOn0 | 1optional

0 is Sunday, 1 is Monday. It defaults to 1.

localestringoptional

Passed to Intl.DateTimeFormat for month and weekday names.

classNamestringoptional

Merged into the grid's container.

DateRange

fromDate | nulloptional

The first date in the range.

toDate | nulloptional

The last date. It stays null while the range is half-made.