Calendar
StableThe whole calendar: week, day, month and agenda views, calendars told apart by pattern, and create, edit and delete.
CalendarApp shows the sample week in the app window with a toolbar (Today, previous and next, the view switch, New event), the calendars by pattern, event details in a popover and a dialog to create or edit. Its one prop, hrefFor, says where the window’s tool links and an event’s linked task go. It saves events and hidden calendars to this browser until you connect a backend; “Reset sample data” brings the sample week back. Phones start on the day view; screens 1024px and wider can show the calendars panel, open from the start at 1536px.
Updated View source
The calendar
import { CalendarApp } from '@rchursin/product/calendar'import { useRouter } from '@rchursin/product/lib/router'import type { KitSlug } from '@rchursin/product/shell/pages'
/** The window's tool links, and an event's linked task, go to each tool's page in this Library */const toolPages: Partial<Record<KitSlug, string>> = { tasks: '/library/tools/tasks-app', calendar: '/library/tools/calendar-app', timer: '/library/tools/timer-app', notes: '/library/tools/notes-app',}
/** * The whole calendar on this week's sample events. Click inside it, then press T for today, * ← → to move, M W D A for the views, N for a new event, or ? for the list. * Changes save to this browser; "Reset sample data" brings the sample week back. */export default function CalendarAppExample() { const { href } = useRouter() const hrefFor = (slug: KitSlug) => { const path = toolPages[slug] return path && href(path) } return <CalendarApp hrefFor={hrefFor} />}Usage
import { CalendarApp, appShortcuts } from '@rchursin/product/calendar'<CalendarApp />API
CalendarApp props
| Prop | Type | Default | Description |
|---|---|---|---|
hrefFor | (slug: KitSlug) => string | undefined | – | Where the window’s tool links (Today, Tasks, Focus, Notes) and an event’s linked task go: your own pages. The default is the product kit’s own #tasks, #calendar … anchors; return undefined to show a tool as plain text. |
Accessibility
Keyboard
| Key | What it does |
|---|---|
| T | Go to today. |
| Left arrowK | Previous week, day or month (two weeks in the agenda). |
| Right arrowJ | Next week, day or month. |
| MWDA | Month, week, day or agenda view. |
| N | New event. |
| ? | Show the shortcuts. |
| Esc | Close the event details or a dialog; focus goes back. |
- The shortcuts are scoped: they only fire while focus is inside the calendar, nothing is open, and you aren’t typing. In the month grid the arrows move between days instead.
- Moving the period and switching views are announced (“Week of Oct 11 to 17, 2026”), and so is showing or hiding a calendar.
- When a change removes the focused element (a view switch, a delete), focus moves to the view, so the keys keep working. After a save, focus goes to the saved event.
- Every event is named in full: “Weekly skill review, Friday 10 to 11 AM, Team calendar”. Calendars differ by pattern (solid, hatched, outline, dashed), never colour.
- Times are labelled with the visitor’s time zone. Deleting shows a toast with Undo.
- The week, the clock and the time zone are the visitor’s own, which a prerendered page can’t know: the static HTML shows the window with an empty body, and the views fill in as soon as the page runs.
Guidelines
Do
- Give it a content column’s width; a week needs about 700px before it scrolls sideways.
- Keep the New event button: clicking a slot is a mouse shortcut, not the only way in.
- Build help and docs from appShortcuts, the list its ? dialog reads.
Don’t
- Don’t put two CalendarApps on one page: they share saved events, and both windows would carry the same region and navigation names.
- Don’t colour the calendars; patterns survive greyscale, print and colour blindness.
In use
Related
- Week and day viewDays across, hours down: a time grid with an all-day row, overlaps side by side, and a line at the current time.
- Month viewThe month as a keyboard grid: up to three events a day, “+N more” for the rest, and pattern squares on phones.
- Event dialogThe create and edit form for an event, in a dialog, and the details popover that leads to it.
- Agenda widgetA mini month with event markers and the chosen day’s agenda, for a dashboard.
- Agenda listEvents grouped by day under headings that can stick, earliest first, each with its time, calendar pattern and people.
- Mini calendarA small month for sidebars and widgets, with up to three squares under days that have events.
- App windowThe RChursin_ app frame: a sidebar with the tools, a title row with a toolbar, and your tool in the body.
Source
The component’s own files, exactly as they run on this site.
/** * The calendar app: week, day, month and agenda views over one set of events, a toolbar, a * sidebar with a mini month and the calendars (told apart by pattern), event details in a * popover, and a dialog to create or edit. Sample events persist per viewer and can be reset. * * Shortcuts (only while focus is inside the window): T today · ← → or K J previous / next · * M W D A views · N new event · ? the list. * * The views show the visitor's own week, clock and time zone, which a prerendered page can't * know. So the server (and the hydration pass) draw the window with an empty body, and the views * fill in straight after; a calendar mounted later in the browser draws them at once. */import { useId, useMemo, useRef, useState } from "react"import { cx } from "../../components/cx"import { calendars, sampleEvents, type CalendarEvent } from "../data/sample"import { Icon } from "../icons/Icon"import { useAnnounce } from "../lib/announce"import { addDays, addMonths,