04core concepts

Views & navigation

Day, week, n-day, month, agenda, year — what each shows, what prev/next step by, and the responsive collapse.

Six calendar-shaped views — day, n-day, week, month, agenda, year — behind one prop, plus a seventh that isn't calendar-shaped at all. KloqView is a string name or a number: pass 3 and you have a 3-day view, up to 14. Switching animates: events shared across views FLIP to their new columns rather than teleporting.

Try them

liveplaygroundnothing is saved
flip a knob, copy the snippet
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
All-day
props
defaultView
Uncontrolled starting view. Ignored when view is set.
weekStartsOn
0 = Sunday … 6 = Saturday.
calendar.tsx
<Kloq>  <Kloq.Toolbar /></Kloq>

The seven shapes

ViewTypeNotes
"day"time gridOne column, full drag engine.
2–14time gridThe n-day view. 2 is the floor because a 1-day n-view is just "day"; 14 the ceiling.
"week"time gridSeven columns, first one set by weekStartsOn (0 = Sunday … 6 = Saturday; default Monday).
"month"month cellsAlways 6 rows of 7 — a stable height beats a jumping one. Neighbouring-month days render dimmed.
"agenda"listA 30-day rolling list from the anchor date.
"year"heat mapTwelve mini-month grids for the anchor's calendar year.
"timeline"resource rowsRooms, staff or machines as rows along a horizontal time axis. See Resource timeline.

Only the time-grid shapes — day, n-day, week — draw the scrollable hour grid and its all-day lane. Month and agenda are selection-and-navigation surfaces; drags there are deliberately not a thing. The timeline draws its own horizontal surface, with the drag engine and a now indicator of its own — next section.

The odd one out: "timeline"

"timeline" shares the drag engine with the time-grid shapes — create, move, resize, all constraint-aware — but nothing else about its layout. Rows are lanes you supply via lanes, not days; there's no all-day lane, because there's no day column for an all-day event to sit above; and its own visible span is set by timelineWindow, which can be tied to the anchor date the way every other view's range is, or pinned independently of it. It's also the one view the responsive collapse leaves alone — there's no narrower n-day span to fall back to, so a timeline just scrolls instead of collapsing. Reach for it when the axis your host cares about is a resource, not a day — see Resource timeline and Resources & lanes.

What ‹ › step by

A step moves by the view's own unit: a day in day view, n days in an n-day view (pages tile rather than overlap), a week in week view, a calendar month in month view, 30 days in agenda, a year in year view, and a day in timeline (one step of the anchor, regardless of how many hours or days timelineWindow derives around it — see Resource timeline for what that anchor drives and what a controlled timelineWindow opts out of). Adding 30 days to a month view would drift off the 1st within a year — so a month anchor is normalised to the 1st, and a year anchor to 1 January, where stepping cannot overflow. All of this is pure and exported, so a custom toolbar can reuse it instead of reimplementing it:

import { stepAnchor, todayAnchor, formatViewTitle, resolveView } from "@/components/kloq";

const next = stepAnchor("month", date, 1);   // the 1st of next month
const today = todayAnchor("month");          // "this month", not "today"
const view = resolveView("week", 1, date);   // ViewDescriptor: days, todayIndex…
const title = formatViewTitle(view);         // "Feb – Mar 2026"

formatViewTitle collapses the parts the two ends of a span share: same month → February 2026, same year → Feb – Mar 2026, spanning years → Dec 2025 – Jan 2026. And what the arrow keys move by is its own prop: navigationKeys="range" (default) pages like the chevrons; "day" makes ←/→ a cursor that always moves one day. PageUp/PageDown always page — they mean "page" everywhere else on the web.

The responsive collapse

A seven-column week squeezed into 360px is unusable — a column is ~43px, narrower than a fingertip. So below 640px of the component's own box (a ResizeObserver, not a media query — a 400px calendar in a desktop sidebar is narrow no matter the viewport) the time-grid views collapse to a single day, the month draws a dot per event instead of titled chips, and the year becomes a month. Between 640px and 900px a week squeezes to three days instead. On by default; responsive={false} opts out, and responsive={{ breakpoint, mediumBreakpoint, mediumDays, collapseTo }} tunes the tiers.

ISO week numbers

showWeekNumbers puts ISO 8601 week numbers in the time grid's gutter corner. ISO, deliberately: weeks start on Monday, week 1 is the week containing the year's first Thursday, and late December can be week 1 of the next year. That is what every European calendar, payroll system and sprint board means by "week 32", and a home-grown ceil(dayOfYear / 7) disagrees with all of them for a few days each year, silently. It is independent of weekStartsOn on purpose, and isoWeek / isoWeekYear are exported for your own chrome.

on this page