02examples
View and date in the URL
Controlled view and date mirrored into the query string, so a link opens the same week and the browser's back button steps the calendar.
Step forward and look at the address bar: ?view=…&date=… follows. Switch
to month view; it follows again. Press the browser's back button and the
calendar steps back to the date you came from. Copy the link, open it in
another tab, and it lands on the same view of the same date — a calendar you
can share. The link always names the view on screen: in a box too narrow for
a week it reads view=day, because a day is what is drawn.
liveView and date in the URL
loading
uses
How it works
viewanddateare controlled. With both props set, ‹ ›, Today, the view switcher, the month picker and the arrow keys all ask throughonViewChange/onDateChange, and nothing moves until the props change. That is what makes the URL authoritative: the calendar cannot drift from it. See Controlled state.- The query string is the state.
searchholds it verbatim;viewanddateare derived from it withuseMemo.navigatebuilds the next string, writes it withwindow.history, and stores it — no router navigation, no server round-trip. A new date ispushState, so back and forward walk the dates you visited; a new view isreplaceState, so it rewrites the entry it is on. Next.js patches both, souseSearchParamselsewhere on the page stays in sync for free. - Back and forward are a
popstatelistener that readslocation.searchback into state. The initial read runs in an effect, never during render, so the server-rendered markup and the first client paint agree; it alsoreplaceStates a normalised query, so a bare or broken link becomes?view=week&date=<today>without adding a history entry. - Parsing is strict.
parseViewaccepts the five named views and an n-day integer insideMIN_N_DAY_VIEW … MAX_N_DAY_VIEW;parseDateacceptsYYYY-MM-DDonly, and rejects a date that would roll over by checking that the parsedDateformats back — throughtoDateOnlyString— to the same string. Anything else falls back to today's week. See Views & navigation. - The chrome is the stock
<Kloq.Toolbar />. Its parts read the same controlled state throughuseKloq(), which is why they need no wiring. See Toolbar & chrome. - The responsive collapse stays on, and the URL follows it. A box under 900px
squeezes a week to three days, one under 640px to a single day, and kloq
reports that effective view through
onViewChange; widen the box and it asks for the week back the same way. Because a view change replaces the history entry, the width can rewrite the link as often as it likes without piling up entries or trapping the back button. See Views & navigation.
Take it further
- Prefer one history entry per visit? Use
replaceStatefor dates too — the link still shares, the back button leaves the page. - Put it in the path instead:
/calendar/week/2026-08-31. The parsing does not change; readusePathname()instead oflocation.search. - Keep the intent in the URL instead of the view on screen: a child of
<Kloq>can readuseKloq().collapsed, and a view change reported while it is true is the width talking, not the user — ignore it and the link saysweekon every device.