Sections
Page Sections
Full-width CMS-driven regions. Each section maps to a componentType and renders via sectionMap.
hero
Full-bleed opening section with optional background image, overlay, heading, subheading, and a single CTA link.
React Router Boilerplate
CMS-driven React,
done right.
A production-ready React Router boilerplate for building fast, flexible apps backed by any CMS.
cardGrid
Responsive grid of Card blocks. Column count is controlled via the cols={[sm, tablet, desktop]} prop — defaults to [1, 2, 3].
Featured
Image + pills + bottom link
image, pills (success + default), link with linkPlacement: bottom — link renders as a button pinned to the base of the card.
Image + pill + wrap link
image, pill (warning), link with linkPlacement: wrap — the entire card is a clickable link element.
Image only — no link
image with no link or pill. Renders as a plain div — backward-compatible baseline.
tabs
Tabbed content panel. Active tab is persisted in URL search params — bookmarkable and refresh-safe.
How it works
Clone the repo, run npm install, and copy .env.example to .env. Point DATA_SOURCE at stub for local development or sanity for a live CMS.
richText
Long-form content section with optional eyebrow, heading, and subheading. Body renders via RichText — accepts Markdown strings or Portable Text arrays.
About this project
A production-ready headless React boilerplate
Built for teams who want a clean starting point — not a framework lock-in.
This boilerplate gives you a complete foundation for building CMS-driven React applications. It's designed to stay out of your way — swap the CMS, extend the design system, and ship with confidence.
What's included
- React Router v7 — Framework mode with full SSR. Data loads server-side on every request — no client waterfalls, no loading spinners on first paint.
- TypeScript strict mode — Component prop contracts drive CMS schemas, not the other way around. Design front-to-back.
- Tailwind CSS v4 — Custom variants for dark mode, compact mode, contained layout, radius scale, and more — all toggled via html class flags with zero JavaScript overhead.
- Sanity CMS — Wired through a DataSource interface. Switch to any headless CMS by implementing a single interface — no changes to components or routes.
- Theme system — Dark mode, accent colors, text size, compact mode, reading mode, and more. Preferences persisted to cookies with an SSR-safe no-flash strategy.
- Component architecture — Three-layer hierarchy (primitives → blocks → sections) with hard boundaries. Sections are the only layer editors ever interact with.
Adding a section in four steps
- Define the interface in types.ts
- Create the component in components/sections/
- Register it in sectionMap
- Add data to your CMS or stub.json
The GROQ query and ComponentRenderer pick it up automatically.
dynamicGrid
Sanity-only section. Each column holds a curated, ordered list of heterogeneous blocks — mix cards, stats, and future block types freely. Nested polymorphism not available in flat CMS adapters.
Why this stack
99.9%
Uptime
Served from CDN edge nodes worldwide.
<100ms
Time to first byte
SSR on every request — no client waterfalls.
Swap the CMS
Implement the DataSource interface. Nothing else changes — routes, components, and types stay untouched.
Extend the design system
One registry entry adds a section everywhere — renderer, stories, and documentation update automatically.
6
Section types
Hero, Card Grid, Accordion, Tabs, Rich Text, and Dynamic Grid — all CMS-driven.
0
Framework lock-in
Plain React Router v7. No proprietary page builder or vendor SDK in the render path.
accordion