05customization
Toolbar & chrome
Kloq.Toolbar, Kloq.Nav, Kloq.Reset and useKloq() — the app bar as opt-in composable parts.
<Kloq> renders no app bar of its own — the chrome is opt-in parts you
compose as children. It used to render its own header, wordmark and all; that
made it an app, not a component. Now naming the product is the host's
business.
The parts
<div className="h-dvh">
<Kloq>
<Kloq.Toolbar>
<h1>My calendar</h1>
<div className="flex items-center gap-2">
<Kloq.Nav />
<Kloq.Reset />
</div>
</Kloq.Toolbar>
</Kloq>
</div>| Part | Type | Notes |
|---|---|---|
Kloq.Toolbar | KloqToolbarProps | A bordered app-bar row above the surface. Pure layout — holds no state. With no children it renders the built-in arrangement: nav left, Reset right, no wordmark. |
Kloq.Nav | { className? } | ‹ › Today, the range title (with its month/year picker), and the view switcher. |
Kloq.Reset | { className? } | Restore the sample events — through the store, so it hits onCommit and persistence like any other change. |
The same components are importable by name — KloqToolbar, KloqNav,
KloqReset — the statics are a convenience. The toolbar's responsiveness is
flex-wrap: below ~640px the nav and your controls stack instead of the view
switcher being squeezed to nothing.
Why children, not siblings
The parts read useKloq() — the same view, anchor date and store the grid is
using — so they have to be inside the provider. Rendering them as children of
<Kloq> buys three things a sibling layout would have to re-solve: the
keyboard layer's ownership test sees a click on Today as landing inside the
calendar, so t / ← / → keep working; design mode's scope and
hover-inspect cover the toolbar; and a host never has to prop-drill view /
onViewChange to reproduce the built-in bar.
useKloq()
The calendar's live view state and navigation actions, as one object —
KloqChrome. Only valid inside <Kloq>: outside it there is no calendar to
describe, and it throws rather than returning a plausible-looking default that
would hide the mistake until a button silently did nothing.
view?ViewDescriptorThe resolved EFFECTIVE view: columns, dates, today's index — after any responsive collapse.
viewSetting?KloqViewThe effective view *setting* ("week", 3, …), not the shape.
intentView?KloqView | undefinedWhat the consumer asked for, when a narrow box is overriding it. undefined when the two agree.
collapsed?boolean | undefinedTrue while the box is overriding the view (three days, a day, or a month).
narrow?boolean | undefinedTrue below the narrow breakpoint — the nav uses a short title.
fits?(view: KloqView) => booleanWhether a view fits the box at its current width; the switcher disables the ones that don't.
date?DateThe anchor date the view is resolved around.
atToday?booleanTrue when today is inside the visible range.
lastStep?StepDirection | nullDirection of the last range step, for directional animation.
step(dir)?(dir) => voidStep the range by one of the current view's units.
goToday()?() => voidMove the range back onto today.
switchView(view)?(view: KloqView) => voidRequest a view change — reports through onViewChange.
jumpToDay(date)?(date: Date) => voidMove the anchor and switch to the day view.
goToDate(date)?(date: Date) => voidMove the anchor, leaving the view alone.
reset()?() => voidRestore the sample events.
openCommand() / openShortcuts()?() => voidOpen ⌘K / the ? shortcuts overlay.
keymap?Keymap | undefinedThe host's keymap overrides, so chrome that advertises a key shows the real binding.
Composing your own bar
import { Kloq, useKloq } from "@/components/kloq";
function SaveIndicator() {
const k = useKloq();
return (
<span className="text-xs text-muted-foreground">
{k.atToday ? "Today" : k.date.toLocaleDateString()}
</span>
);
}
<Kloq>
<Kloq.Toolbar>
<MyLogo />
<div className="flex items-center gap-2">
<SaveIndicator />
<Kloq.Nav />
<MyAccountMenu />
</div>
</Kloq.Toolbar>
</Kloq>Anything inside the toolbar can call useKloq() — your components and the
built-ins read the same context, so a custom Today button is
onClick={k.goToday} and nothing more. Note the distinction the shape
encodes: view is what is drawn, viewSetting is the current setting, and
intentView remembers what you asked for while a narrow box overrides it —
chrome that steps the range or highlights the active view should read the
effective one, or ‹ › would step by a week while showing a day.