02examples

Calendar in an app layout

The calendar as one route of a product — sidebar nav, a header built from useKloq(), and a container that gives it a real height.

A mock product: a sidebar with four routes, "Calendar" active, and the calendar filling the rest. The header is the product's — its title, ‹ › Today, a view switcher, Share and an avatar — but every control in it reads the calendar it sits inside. Step the range and the heading changes.

liveCalendar in an app layoutclassNamechildrenuseKloqKloqToolbar
loading

How it works

The shell is a CSS grid with a real height: grid h-[36rem] sm:grid-cols-[11rem_minmax(0,1fr)]. The right cell is min-h-0 min-w-0 so the grid track, not its content, decides its size, and <Kloq> — which is h-full and never reaches for the window — fills it. That is the whole of "the container is the contract": give the component a box with a height and it renders into it.

<Kloq> renders no app bar of its own. Header is passed as children, so it lands above the surface inside the calendar's provider, and it calls useKloq() for everything it shows: view for the heading via formatViewTitle, step / goToday / atToday for the range controls, viewSetting and switchView for the switcher. KloqToolbar is only the bordered row. See toolbar & chrome.

The cell is about 520px wide here. The stock responsive collapse would force a single day below 640px, but three 150px columns read fine, so responsive={{ breakpoint: 480 }} lowers that tier for this box — the medium tier still turns a seven-column week into three days. The switcher disables what does not fit with k.fits(view), the same call the built-in switcher makes.

Nothing in the sidebar knows about the calendar. It is plain markup outside <Kloq>, which is where product chrome that does not need calendar state belongs.

Take it further

Move view and date into your router and pass them as controlled props — View and date in the URL does exactly that — and the header keeps working unchanged, because useKloq() reports the effective state either way.

on this page