Calendar
A themeable date calendar with keyboard navigation, range selection, and locale support — no date library lock-in, OKLCH-tokened surfaces.
Colors (inline)
Real use · date + range pickers
Using Calendar
Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.
Plain HTML — CSS classes
The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Calendar is styled but inert: its behavior comes from calendar. For that behavior with no framework, use the node-tree path below.
/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";Root class calendar, with 21 modifiers:
.calendar.calendar-accent.calendar-day.calendar-error.calendar-grid.calendar-header.calendar-info.calendar-month.calendar-months.calendar-nav.calendar-neutral.calendar-popup.calendar-primary.calendar-secondary.calendar-success.calendar-title.calendar-warning.calendar-weekday.calendar-weekdays.date-field.date-field-icon.date-field-value
React
Typed components over those same classes, with behavior and accessibility from Base UI.
npm i @wizeworks/silicaui-reactimport { Calendar } from "@wizeworks/silicaui-react";Props
| Prop | Type | Required | Description |
|---|---|---|---|
| mode | CalendarMode | no | single (default) selects one date; range selects a start/end pair. |
| value | CalendarValue | no | Controlled selection — a Date in single mode, a DateRange in range mode. |
| defaultValue | CalendarValue | no | Uncontrolled initial selection. |
| onValueChange | (value: CalendarValue) => void | no | Fires with the new selection. |
| month | Date | no | Controlled visible (left-most) month. |
| defaultMonth | Date | no | Uncontrolled initial visible month. |
| onMonthChange | (month: Date) => void | no | — |
| numberOfMonths | number | no | How many month grids to show side by side (default 1; 2 for range). |
| weekStartsOn | Weekday | no | 0 = Sunday (default) … 6 = Saturday. |
| min | Date | no | Selectable bounds (inclusive). |
| max | Date | no | — |
| isDateDisabled | (date: Date) => boolean | no | Per-date disable predicate. |
| locale | string | no | BCP-47 locale for month/weekday names (default: runtime locale). |
| color | CalendarColor | no | Accent for the selection. |
| className | string | no | — |
| "aria-label" | string | no | — |
Source of the demo above
The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.
Show source
import { useState } from "react";
import {
Calendar,
DatePicker,
DateRangePicker,
} from "@wizeworks/silicaui-react";
import type { DateRange } from "@wizeworks/silicaui-react";
import { Section, Row } from "../lib/Section";
import { COLORS } from "../lib/data";
export function CalendarDemo() {
const [date, setDate] = useState<Date | null>(new Date(2026, 6, 14));
const [pickedDate, setPickedDate] = useState<Date | null>(null);
const [range, setRange] = useState<DateRange>({ start: null, end: null });
return (
<>
<Section title="Colors (inline)">
<Row>
{COLORS.slice(0, 3).map((color) => (
<Calendar
key={color}
color={color}
value={date}
onValueChange={(v) => setDate(v as Date)}
/>
))}
</Row>
</Section>
<Section title="Real use · date + range pickers">
<Row>
<DatePicker
color="primary"
value={pickedDate}
onValueChange={setPickedDate}
placeholder="Pick a date"
/>
<DateRangePicker
color="primary"
value={range}
onValueChange={setRange}
placeholder="Pick a range"
/>
</Row>
</Section>
</>
);
}Vanilla — node tree to HTML
calendar — Calendar carries the behavior directly; DatePicker/ DateRangePicker are the SAME calendar shell nested inside a popover root's panel (a calendar behavior root nested inside a popover one — ownParts already stops at nested behavior boundaries, so this needs no extra code, same composition trick as Lightbox nesting inside modal). Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.
npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviorsimport { atom, toHtml } from "@wizeworks/silicaui-html";
const node = atom("Calendar", "calendar", { /* props */ });
const markup = toHtml(node);Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "calendar calendar-primary" rather than passing a colour as a prop.
- Takes children
- no
- Hydrated by
calendar
Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.
The full API for Calendar, on every path, is available through the Silica MCP server.