Reusable sections—hero, features, testimonials, FAQs, CTAs—are how modern marketing sites scale without duplicating work. The trick is to model these page sections as blocks in your headless CMS so editors can assemble pages, while your frontend renders a consistent design system.
This guide shows a clean, scalable approach you can use in ElmapiCMS (or any headless CMS) and render in frameworks like Next.js, Nuxt, or Astro.
Table of Contents
- What “blocks” are (and when to use them)
- Two core approaches: flexible vs constrained
- Recommended model: Page + Sections + Section Types
- How to model common sections
- Editor UX tips
- Frontend rendering pattern (component map)
- SEO considerations
- Pitfalls to avoid
What “blocks” are (and when to use them)
Blocks are structured, reusable page sections that can be ordered and repeated on a page. Examples:
- Hero
- Features grid
- Pricing table
- Testimonials
- FAQ accordion
- Call-to-action (CTA)
Use blocks when:
- You have many pages with similar patterns (landing pages, solution pages).
- You want non-developers to assemble pages from approved building blocks.
- You want to reuse sections across pages without copy/paste drift.
Avoid blocks for:
- Long-form editorial posts (use rich text/MDX).
- Highly bespoke pages where the cost of modeling outweighs the benefit.
Two core approaches: flexible vs constrained
There are two viable ways to model sections:
1) Flexible blocks (best for marketing teams)
- A Page contains an ordered array/list of Sections
- Each section has a
type(hero, faq, cta, etc.) - Each section type has its own fields
Pros: maximum flexibility and reuse.
Cons: you must enforce consistency with validation + frontend component mapping.
2) Constrained pages (best for strict design systems)
- A Page has fixed fields:
hero,features,faq,cta - You decide what every page must include
Pros: easy rendering, fewer states.
Cons: harder for editors, less composable, more duplication across page types.
Most teams end up with flexible blocks but constrain them with:
- a limited set of section types
- per-page allowed section types
- “required sections” rules in editorial workflow
Recommended model: Page + Sections + Section Types
Here’s a clean mental model (works even if your CMS stores it differently):
- Page
titleslugseo(meta title, description, canonical, OG image)sections[](ordered)
Each item in sections[]:
type(string enum):hero,features,testimonials,faq,cta, …id(unique)data(fields for that type)
If your CMS supports relations, you can also model it as:
- Page ↔ many PageSections
- PageSection ↔ one SectionType + fields
The goal is the same: you can add, reorder, reuse, and version sections.
How to model common sections
Below are field sets that scale well and keep editors productive.
Hero section
headline(string)subheadline(text)primaryCtaLabel(string)primaryCtaHref(string)secondaryCtaLabel(string, optional)secondaryCtaHref(string, optional)image(media, optional)variant(enum: centered, split, minimal)
Features grid
title(string, optional)items[]title(string)description(text)icon(string or media)
Testimonials
title(string, optional)items[]quote(text)name(string)role(string, optional)company(string, optional)avatar(media, optional)
FAQ
title(string, optional)items[]question(string)answer(rich text or text)
CTA
headlinebody(optional)ctaLabelctaHrefvariant(enum: primary, secondary, subtle)
Tip: keep section schemas small. Large “do everything” sections become hard to render and harder to maintain.
Editor UX tips
To make blocks usable in practice:
- Use section previews: show
type + headline/titleso reordering is safe. - Add sensible defaults: prefill labels like “Get started” and empty arrays like
items. - Limit variants: 2–3 variants per section is plenty.
- Create “allowed sections per page type” rules: e.g. Pricing pages can use pricing + faq + cta; blog pages can’t.
- Provide content guidance: placeholder text and short field descriptions (“Keep headline under 60 characters”).
Frontend rendering pattern (component map)
The standard approach is a type-to-component mapping:
- Fetch a page by slug (and include its
sections[]). - Loop through
sections[]. - Render the component that matches
section.type.
Example pseudo-code:
const SECTION_COMPONENTS = {
hero: HeroSection,
features: FeaturesSection,
testimonials: TestimonialsSection,
faq: FaqSection,
cta: CtaSection,
} as const;
return sections.map((section) => {
const Component = SECTION_COMPONENTS[section.type] ?? UnknownSection;
return <Component key={section.id} {...section.data} />;
});
Two important implementation details:
- Forward-compat: add
UnknownSectionso new section types don’t crash production. - Type safety: if you use TypeScript, make
section.typea union of known strings and validate server-side.
SEO considerations
Blocks are great for SEO when:
- You model SEO fields per page (title, description, canonical).
- You model headings intentionally:
- Hero headline is usually H1
- Section titles are H2/H3 depending on structure
- You avoid rendering empty/placeholder sections.
For structured data:
- FAQs can output FAQ schema JSON-LD
- Breadcrumbs can output Breadcrumb schema
(We’ll cover JSON-LD in a dedicated post.)
Pitfalls to avoid
- One mega-block: a single “content” section with 50 optional fields becomes unmaintainable.
- Too many section types: editors get decision fatigue; devs get component sprawl.
- No validation: require key fields for each type (e.g. hero headline, CTA href).
- Client-only fetching: keep CMS tokens server-side; use server components or API routes.
Related posts:
- How to Model Navigation Menus in a Headless CMS (and Render in Next.js) – Model header and footer navigation as CMS content and render with
next/link. - JSON-LD for Headless CMS Content: Article, FAQ, Breadcrumb, and Product Schema – Add structured data to block-based pages (FAQ schema, Breadcrumb schema).
- How to Model Relations in a Headless CMS (Beginner Guide) – Understand relations between content types before building blocks.
- How to Build RAG with a Headless CMS – Well-structured blocks and content modeling improve RAG retrieval quality.
- Multi-site Headless CMS Architecture – Share block schemas across multiple sites and brands.
