Loading...

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

Card image 1
NewFeatured

Image + pills + bottom link

image, pills (success + default), link with linkPlacement: bottom — link renders as a button pinned to the base of the card.

Card image 2
Sale

Image + pill + wrap link

image, pill (warning), link with linkPlacement: wrap — the entire card is a clickable link element.

Card image 3

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

  1. React Router v7 — Framework mode with full SSR. Data loads server-side on every request — no client waterfalls, no loading spinners on first paint.
  2. TypeScript strict mode — Component prop contracts drive CMS schemas, not the other way around. Design front-to-back.
  3. 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.
  4. Sanity CMS — Wired through a DataSource interface. Switch to any headless CMS by implementing a single interface — no changes to components or routes.
  5. 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.
  6. 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

  1. Define the interface in types.ts
  2. Create the component in components/sections/
  3. Register it in sectionMap
  4. 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

Collapsible FAQ-style list of AccordionItem blocks. Each item manages its own open state.

Frequently Asked Questions