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 a week forward and look at the address bar: ?view=week&date=… follows. Switch to month view; it follows again. Press the browser's back button and the calendar goes back with it. Copy the link, open it in another tab, and it lands on the same view of the same week — a calendar you can share.

liveView and date in the URLviewdateonViewChangeonDateChange
loading

How it works

  • view and date are controlled. With both props set, ‹ ›, Today, the view switcher, the month picker and the arrow keys all ask through onViewChange / 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. search holds it verbatim; view and date are derived from it with useMemo. navigate builds the next string, pushes it with window.history.pushState, and stores it — no router navigation, no server round-trip. Next.js patches pushState, so useSearchParams elsewhere on the page stays in sync for free.
  • Back and forward are a popstate listener that reads location.search back into state. The initial read runs in an effect, never during render, so the server-rendered markup and the first client paint agree; it also replaceStates a normalised query, so a bare or broken link becomes ?view=week&date=<today> without adding a history entry.
  • Parsing is strict. parseView accepts the five named views and an n-day integer inside MIN_N_DAY_VIEW … MAX_N_DAY_VIEW; parseDate accepts YYYY-MM-DD only, and rejects a date that would roll over by checking that the parsed Date formats back — through toDateOnlyString — 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 through useKloq(), which is why they need no wiring. See Toolbar & chrome.
  • responsive={false} keeps the URL honest in this narrow column. With the collapse on, a box under 900px squeezes a week to three days and reports 3 through onViewChange — the effective view, not the intent — and that is what would land in the link. See Views & navigation.

Take it further

  • Prefer one history entry per visit? Swap pushState for replaceState in navigate — 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; read usePathname() instead of location.search.
  • Turn the collapse back on for a real app, and keep the intent in the URL: a child of <Kloq> can read useKloq().collapsed, and a view change reported while it is true is the width talking, not the user.

on this page