Block Models

A block model defines the schema for a reusable, composable content component — a self-contained section or UI element that editors can add to pages. Blocks are the building blocks of flexible page layouts. A hero banner, a call-to-action card, a features grid, a testimonial carousel — each of these is a block model with its own fields and its own template.

This page covers how block models work, how they're used inside pages and entries, nested block architecture, composability across models, and how to decide between blocks and other structural field types.


What Is a Block Model

A block model is a content type definition that represents a discrete, reusable section of content. Unlike pages, blocks don't have URLs. Unlike entries, blocks don't exist independently in a content list. Blocks are embedded inline within other content — they live inside the pages and entries that use them.

When you create a block model, you configure:

A name and handle — The name is what editors see when choosing blocks in the editor. The handle is the identifier used in templates and API responses.

Fields — The data structure for the block's content. A hero block might have fields for heading, subheading, background image, and a CTA button group. A testimonial block might have fields for quote text, author name, author photo, and company.

The result is a content component that can be used across your entire site. You define the block model once, and it becomes available to any page or entry model that includes it in its allowed block types.


Blocks Inside Pages

The primary use of blocks is within page models through dynamic block fields. When a page model includes a dynamic block field, it specifies which block types editors are allowed to add. Editors then compose the page by selecting and arranging blocks from that allowed set.

A homepage page model might allow hero, features, testimonials, pricing, CTA, and FAQ blocks. An editor building the homepage adds the blocks they need, fills in the content for each one, and arranges them in the desired order. The result is a page whose layout is unique to that instance but whose individual sections are all structurally governed by their block models.

Each block instance within a page is independent. An editor can add three different CTA blocks to the same page, each with different content. They can reorder blocks, hide blocks without deleting them, and remove blocks entirely. The dynamic block field gives editors full control over composition while the block models maintain structural consistency for each section type.

Dynamic Blocks


Blocks Inside Entries

Blocks aren't limited to pages. Entry models can also include block fields, which lets you build composable structures in non-routable content.

A "Service" entry model might include a block field that allows editors to add feature blocks, making each service entry composable. A "Product" entry model might include blocks for specification sections, comparison tables, or highlight panels.

The mechanics are the same as in pages — you add a block field to the entry model, configure the allowed block types, and editors compose the entry's content from those blocks. This is useful when entries need flexible, section-based content rather than a fixed set of fields.


Nested Blocks

Blocks can contain other blocks. A block model can include a block field that references other block types, creating a hierarchical content structure where sections contain sub-sections.

This enables complex but governed layouts. A "Section" block might allow "Card" blocks inside it, creating a grid of cards within a section. A "Tabs" block might allow "Tab Panel" blocks, each containing its own content. A "Two Column" block might allow different block types in each column.

Page
└── Dynamic Block Field
    ├── Hero Block
    │   └── Fields (heading, image, CTA)
    ├── Features Section Block
    │   └── Block Field → Feature Card Blocks
    │       ├── Feature Card (icon, title, description)
    │       ├── Feature Card (icon, title, description)
    │       └── Feature Card (icon, title, description)
    └── Tabs Block
        └── Block Field → Tab Panel Blocks
            ├── Tab Panel (label, content)
            └── Tab Panel (label, content)

Nesting depth is up to you, but keep the editor experience in mind. Two levels of nesting — a section containing cards — is intuitive. Three or four levels can make the editing interface difficult to navigate. Design your block architecture to balance structural richness with editorial usability.


Block Composability

A single block model can be used across multiple page models, multiple entry models, or both. This is one of the most powerful aspects of the block system — you define a component once and reuse it everywhere.

A "CTA" block model with fields for heading, body text, button label, and button URL can appear on the homepage, on blog posts, on product pages, and on landing pages. The block's structure and template are defined once. Any page model that allows the CTA block gives editors access to it.

Structural Changes Propagate

When you modify a block model's structure — adding a field, removing a field, or changing a field type — the change applies everywhere that block is used. If you add a "background color" field to the CTA block, every page and entry that includes CTA blocks gains that field in its editor.

This is a design system principle applied to content. Block models act as your content components, and changes to the component definition propagate across the entire site. It means you maintain content structures in one place rather than updating the same field set on every model that uses it.

Building a Block Library

As your site grows, your block models form a library of content components. A well-designed block library might include:

Layout blocks — Hero, two-column, three-column, full-width section, sidebar layout. These define spatial arrangement.

Content blocks — Rich text section, image with caption, video embed, blockquote. These carry primary content.

Interactive blocks — Accordion, tabs, carousel, before/after slider. These provide interactive patterns.

Conversion blocks — CTA banner, pricing table, contact form, newsletter signup. These drive user action.

Social proof blocks — Testimonial, client logos, case study highlight, statistics counter. These build credibility.

Not every site needs all of these. Start with the blocks your content requires and add new block models as needs emerge. The block library grows naturally as you identify repeating patterns in your pages.


View Template Separation

Each block model has its own EJS template in the site builder. This is a key architectural decision — the rendering logic for a block lives with the block, not with the pages that use it.

When the site builder compiles a page that contains dynamic blocks, it renders each block instance using the block's own template and injects the output into the page. The page template doesn't need to know how to render a hero banner or a pricing table — it delegates that to the block templates.

This separation has practical benefits. Changing how a testimonial block renders only requires editing the testimonial block template. The change takes effect everywhere the block appears, across all pages and entries. You don't need to find and update rendering logic in every page template that might include testimonials.

Block templates receive the block's field data as the item variable, just like page and entry templates. They also have access to the full site content, so a block template can reference entries, images, options, or other data beyond what's stored in the block's own fields.

Model TemplatesTemplate Context and Data Access


When to Use Block vs Group

Blocks and groups both organize fields into logical units, but they serve different purposes and have different capabilities. Choosing between them depends on whether you need reusability and composability or just field organization.

Use a block when:

  • The component appears across multiple models. A CTA section used on the homepage, blog posts, and landing pages should be a block — define it once, use it everywhere.
  • Editors need to add, remove, reorder, or hide instances. Dynamic block fields give editors composition control that groups don't provide.
  • The component has its own visual template. Blocks get their own EJS template in the site builder, making rendering modular and maintainable.
  • You want structural changes to propagate. Modifying a block model updates every instance across the site.

Use a group when:

  • The fields are specific to one model and won't be reused elsewhere. An SEO metadata group on a page model doesn't need to be a block.
  • The structure is fixed — editors shouldn't add or remove instances. Groups are static containers; their fields always appear in the editor.
  • You just need visual organization in the editor. Groups let you cluster related fields (e.g., address fields, social links) without the overhead of a separate model.

The distinction is straightforward: blocks are reusable components, groups are organizational containers. If you find yourself duplicating the same set of fields across multiple models, that's a signal to extract them into a block model.

Capability Block Group
Reusable across models Yes No
Own template in site builder Yes No
Editors can add/remove/reorder Yes (via dynamic block field) No
Changes propagate across site Yes No
Nesting support Yes Yes
Best for Composable sections, UI components Field organization within a model

Block Models and the Content API

In API responses, blocks appear as objects within a dynamic block field array. Each block object includes a type identifier and the block's field data, giving your frontend the information it needs to select the right component for rendering.

const page = client.getPage('/');
// page.sections → [
//   { _type: 'hero', heading: 'Welcome', image: { url: '...' }, cta: { ... } },
//   { _type: 'features', items: [...] },
//   { _type: 'testimonials', quotes: [...] },
//   { _type: 'cta', heading: 'Get Started', buttonLabel: 'Sign Up', buttonUrl: '/signup' }
// ]

Your frontend iterates over the block array and renders the appropriate component for each type. In a React application, this typically maps to a component lookup:

const blockComponents = {
  hero: HeroSection,
  features: FeaturesGrid,
  testimonials: TestimonialCarousel,
  cta: CTABanner,
};

page.sections.map(block => {
  const Component = blockComponents[block._type];
  return Component ? <Component key={block._id} {...block} /> : null;
});

Nested blocks appear as nested arrays within the parent block's data, following the same structure recursively.

Content API@sleekcms/client


What's Next

  • Page Models — Routable content types with URL paths and slug-based collections.
  • Entry Models — Structured, non-routable content for shared data like authors, categories, and settings.
  • Content Field Types — The full set of field types available in page, entry, and block models.
  • Dynamic Blocks — Deep dive into configuring dynamic block fields and the editor experience.
  • Group Fields — Organizing fields within a model without the overhead of a separate block.
  • Content Editing — The editing experience for content creators working with blocks.