implement
Calendar

Calendar

A month grid for picking a single date, or several.

Appointment date August 2026
SMTWTFS
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
import { signal } from "@implementjs/core";
import { today, type CalendarDate } from "@implementjs/primitives";
import { Calendar } from "@/lib/components/ui/calendar";

export default function CalendarDemo() {
	const value = signal<CalendarDate | null>(today());

	return Calendar({ value, calendarLabel: "Appointment date" });
}

Installation

npx jsrepo add @implementjs/ui/calendar

jsrepo pulls button along with it, and installs @implementjs/lucide.

Usage

The styled calendar is assembled, not composed: Calendar renders the navigation, the weekday header, and the day grid itself, so a whole date picker is one call. Every root prop from the primitive is forwarded — value, type, minValue, isDateUnavailable, numberOfMonths, and the rest.

import { signal } from "@implementjs/core";
import { today, type CalendarDate } from "@implementjs/primitives";
import { Calendar } from "@/lib/components/ui/calendar";

const value = signal<CalendarDate | null>(today());

Calendar({ value, calendarLabel: "Appointment date" });

Multiple dates

type: "multiple" turns value into a Signal<CalendarDate[]>:

const dates = signal<CalendarDate[]>([]);

Calendar({ type: "multiple", value: dates, calendarLabel: "Available days" });

Building your own layout

The file exports its pieces so you do not have to fork it to rearrange them. calendarRootClasses and calendarDayClasses are the class strings; CalendarNav() is the header row; CalendarMonthGrid(month, weekdays) is one month, weekday header included. Its trailing arguments — Cell, Day, dayClasses — are the seams the range calendar uses to swap in its own cells.

Drop down to the primitive's own parts when you want a different structure entirely; Calendar covers them.

API Reference

Every prop the styling does not consume is forwarded to the Calendar primitive, so the tables below are the whole surface — the behavior props and the styling ones together.

Calendar

A calendar, fully assembled: month navigation, the weekday header, and the day grid are built in, so the styled root takes children of its own only through the primitive's render function. Every root prop below is forwarded. Renders a Div; extra props are forwarded onto it.

PropTypeDefaultDescription
type"single" | "multiple""single"Whether one date is selected, or several can be.
valueSignal<CalendarDate | null> | Signal<CalendarDate[]>The selection. CalendarDate | null when type is "single", CalendarDate[] when "multiple". Pass a signal to control it from outside.
maxDaysnumberOnly for type "multiple": the most dates that can be selected. Exceeding it restarts the selection at the clicked date.
onDateSelect() => voidRuns after a date is selected (not after a deselection).
placeholderSignal<CalendarDate> | CalendarDatetodayThe date the view starts on and keyboard focus follows. Pass a signal to control the view from outside.
minValueCalendarDateThe earliest selectable date. Earlier dates are disabled.
maxValueCalendarDateThe latest selectable date. Later dates are disabled.
isDateDisabled(date: CalendarDate) => booleanMarks dates as disabled: not selectable and skipped by the keyboard.
isDateUnavailable(date: CalendarDate) => booleanMarks dates as unavailable: focusable and rendered, but not selectable. Sets data-unavailable.
preventDeselectbooleanfalseWhether clicking a selected date again keeps it selected.
disabledSignal<boolean> | booleanfalseDisables the whole calendar.
readonlySignal<boolean> | booleanfalseThe value can be read but not changed.
fixedWeeksbooleanfalseAlways render six weeks per month so the grid height never changes.
numberOfMonthsnumber1How many consecutive months are rendered.
pagedNavigationbooleanfalseWhether prev/next move by numberOfMonths months instead of one.
weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 6The day the week starts on, 0 being Sunday. Defaults to the locale's week start where the runtime knows it.
weekdayFormat"narrow" | "short" | "long""narrow"The Intl width of the weekday names handed to the render function.
disableDaysOutsideMonthbooleantrueWhether the leading and trailing days outside the month are disabled.
localestring"en-US"BCP 47 locale tag used for all formatting.
calendarLabelstring"Event"Prefixed onto the visible month to label the calendar for assistive technology.
monthFormatIntl.DateTimeFormatOptions["month"] | ((month: number) => string)"long"How the heading and month select format month names.
yearFormatIntl.DateTimeFormatOptions["year"] | ((year: number) => string)"numeric"How the heading and year select format years.
Data attributeValue
[data-calendar-root]Present
[data-invalid]Present when the value is disabled or unavailable
[data-disabled]Present when disabled
[data-readonly]Present when readonly

CalendarNav

The header row the root renders — previous button, month heading, next button. Exported so a custom layout can reuse it. Takes no arguments.

CalendarMonthGrid

One month's grid, weekday header included: CalendarMonthGrid(month, weekdays, Cell?, Day?, dayClasses?). The trailing arguments are what the range calendar swaps out to get its own cells and day classes.