Dynamic Blocks
Dynamic blocks are how editors compose page layouts from pre-built sections. A dynamic block field turns a page into an ordered stack of content sections — a hero, a features grid, a testimonial carousel, a call-to-action banner — where editors control which sections appear, in what order, and with what content. Each section is a block instance with its own fields and its own view template.
This is the mechanism that lets content teams build complete pages visually, without developer involvement for each new page. Developers define the block models and their templates. Editors assemble pages from those blocks, with a live preview alongside the editor showing exactly how the page will render.
This page covers how dynamic blocks work, how to configure allowed block types, the editor experience, how pages are rendered as section stacks in the site builder, and how dynamic block data flows through the content API.
What Are Dynamic Blocks
A dynamic block field is a special field type you add to a page model (or entry model) that lets editors compose content from a set of allowed block types. Unlike fixed fields where every page of a model has the same structure, a dynamic block field lets each page instance have a different composition of sections.
When an editor creates a page with a dynamic block field, they see an interface where they can add block sections from the allowed set, fill in each block's fields, reorder sections by dragging, hide sections without deleting them, and remove sections entirely. The result is a page whose layout is unique to that instance but whose individual sections are all structurally defined by their block models.
This is the core page-building experience in SleekCMS. It combines the governance of structured content modeling — every section has a defined schema with typed fields — with the editorial flexibility of a visual page builder.
Configuring Allowed Block Types
When you add a dynamic block field to a model, you configure which block types editors can use. This is your primary governance control — editors can only add blocks you've explicitly allowed.
There are three selection modes:
All blocks — Every block model in the site is available. This is the most permissive option and is typically used for general-purpose landing page models where editors need maximum flexibility. As you add new block models to the site, they automatically become available in this field.
Blocks with prefix — Only block models whose handle starts with a specific prefix are available. This is a convention-based approach that scales well. If you prefix all blog-related blocks with blog- (e.g., blog-hero, blog-callout, blog-code-sample), a dynamic block field configured with the blog- prefix automatically includes any new block you create with that prefix. You don't need to reconfigure the field when you add blocks — just follow the naming convention.
Selected blocks — You explicitly choose which block models are available. This gives you the tightest control and is the most common configuration. A homepage model might allow hero, features, testimonials, pricing, cta, and faq blocks. A blog post model might allow callout, code-sample, image-gallery, and cta blocks. Each model gets exactly the blocks that make sense for its content type.
The selection mode is a modeling decision you make once per dynamic block field. You can change it later — switching from selected blocks to prefix-based, or adding new blocks to the selected list — without affecting existing content.
Pages as Stacks of Sections
With dynamic blocks, a page is conceptually a stack of sections. Each section is a block instance with its own content, and the page's layout is the sequence of those sections from top to bottom.
This model maps directly to how modern marketing pages, landing pages, and content-rich sites are built. A typical page might look like:
Page: Homepage
├── Hero Block → Full-width hero with heading, subheading, CTA
├── Logos Block → Client logo strip
├── Features Block → Three-column feature grid
├── Testimonials Block → Carousel of customer quotes
├── Pricing Block → Pricing tier comparison
├── FAQ Block → Accordion of common questions
└── CTA Block → Final call-to-action banner
Each of these sections is an independent block instance. The hero has its own fields (heading, subheading, background image, CTA button). The pricing block has its own fields (tiers, prices, feature lists). They don't share data — they're self-contained sections that together form the page.
An editor building this page adds each block type in order, fills in the content for each section, and sees the result immediately in the preview panel. A different landing page might use only three of these blocks, or arrange them in a different order, or include two CTA blocks in different positions. Every page instance can have its own composition.
The Editor Experience
The dynamic block editor is designed for visual page composition. Editors work in a split-panel interface with the content editor on one side and a live preview on the other.
Adding Sections
Editors add a new section by selecting a block type from the allowed set. The block's fields appear in the editor, and the corresponding section renders immediately in the preview. Editors fill in the content — heading text, images, button labels — and see the rendered section update in real time.
Reordering Sections
Sections can be reordered by dragging them to a new position. Moving the testimonials block above the pricing block is a drag operation, and the preview updates to reflect the new order. This makes it easy to experiment with page flow without re-entering content.
Hiding Sections
Editors can hide a section without deleting it. A hidden section retains all its content but doesn't render in the preview or on the published page. This is useful for seasonal content — a holiday promotion banner that gets hidden after the campaign ends and can be unhidden next year with all its content intact. It's also useful during drafting, when editors want to prepare sections in advance and reveal them later.
Removing Sections
Editors can remove a section entirely, which deletes it and its content from the page. This is a permanent action — unlike hiding, removing a section means its content is gone.
Live Preview
The preview panel shows the page as it will appear on the published site. Because each block model has its own view template in the site builder, the preview renders the actual HTML output — not a wireframe or approximation. Editors see real typography, real layout, real images. This side-by-side workflow means editors don't need to publish or preview in a separate tab to see how their changes look.
Rendering Dynamic Blocks in Templates
In the site builder, dynamic blocks are rendered using the render() helper function. When a page model has a dynamic block field — typically called sections — the page template delegates rendering to each block's own template with a single call.
The render() Function
The page template renders all dynamic block sections with:
<%- render(item.sections) %>
This single line iterates over every block instance in the sections field, looks up the corresponding block model's EJS template, renders it with the block's field data as item, and concatenates the HTML output. The page template doesn't need to know what types of blocks are present or how to render them — it delegates entirely to the block templates.
How It Works End to End
The full rendering pipeline for a page with dynamic blocks follows this flow:
1. Layout template — The shared layout wraps the page with the outer HTML shell: <html>, <head>, navigation, footer.
2. Page template — The page template renders the page's fixed fields (title, metadata) and calls render(item.sections) to output the dynamic block area.
3. Block templates — Each block in the sections array is rendered by its own template. A hero block uses the hero template, a pricing block uses the pricing template. Each block template receives its own field data as item.
Layout Template
└── Page Template
├── Fixed fields (title, meta)
└── render(item.sections)
├── hero.ejs → item = { heading, subheading, image, cta }
├── features.ejs → item = { items, layout, heading }
├── testimonials.ejs → item = { quotes, style }
└── cta.ejs → item = { heading, buttonLabel, buttonUrl }
A Practical Example
A simple page template for a landing page model:
<article>
<h1><%= item.title %></h1>
<%- render(item.sections) %>
</article>
A hero block template that renders one of the sections:
<section class="hero" style="background-image: url('<%= item.image.url %>')">
<div class="hero-content">
<h2><%= item.heading %></h2>
<p><%= item.subheading %></p>
<a href="<%= item.cta_url %>" class="btn btn-primary">
<%= item.cta_label %>
</a>
</div>
</section>
A CTA block template:
<section class="cta-banner">
<h2><%= item.heading %></h2>
<a href="<%= item.button_url %>" class="btn">
<%= item.button_label %>
</a>
</section>
The page template stays minimal. All the section-level rendering logic lives in the block templates, where it's modular and reusable. The same hero block template renders the hero section on the homepage, on a product landing page, and on a campaign page — wherever that block type is used.
→ Site Builder → Model Templates → Template Context and Data Access
Layout Flexibility vs Governance
Dynamic blocks create a spectrum between fully flexible and fully governed page layouts. Where you land on that spectrum is a modeling decision.
Maximum flexibility — A dynamic block field set to "all blocks" with a large block library lets editors build almost any page layout. This works well for marketing teams that need to create diverse landing pages quickly, but it relies on editors making good composition choices.
Moderate governance — A dynamic block field with a curated set of 5–10 selected blocks gives editors meaningful layout options while ensuring every section on the page is one you've designed and templated. This is the most common setup — enough flexibility for varied pages, enough structure to maintain design consistency.
Tight governance — A dynamic block field with only 2–3 allowed blocks, or a page model with mostly fixed fields and a small dynamic area, gives editors limited composition control. This works for content types where the layout should be mostly consistent across instances — blog posts where only the body section is composable, or product pages with a fixed structure and one flexible area.
You can also combine fixed fields and dynamic blocks on the same page model. A blog post model might have fixed fields for title, author, publish date, and featured image, plus a dynamic block field for the article body. The header structure is consistent across all posts, while the body content is composable.
Design System Alignment
Dynamic blocks naturally align with design system thinking. Each block model is a component with defined fields, and each block template is the component's rendering implementation. The block library becomes your site's component library, and the allowed blocks on each page model are the components available in that context.
This means your design system and your content model stay in sync. When a designer adds a new section type to the design system, you create a corresponding block model with the right fields and a template that implements the design. The block immediately becomes available to editors on any page model that allows it.
Changes to a component's design — updating the testimonial card layout, adjusting the CTA banner's spacing — are made in the block template. The change takes effect everywhere that block is used, across all pages. Editors don't need to do anything; the content stays the same and the rendering updates.
When to Use Dynamic Blocks
Dynamic blocks are the right choice when page layouts vary across instances and editors need to control composition. They're not always necessary.
Use dynamic blocks when:
- Different pages of the same type need different section layouts. Landing pages, marketing campaigns, and long-form content pages are classic cases.
- Editors need to add, remove, or reorder sections without developer help. The visual page builder workflow depends on dynamic blocks.
- You want a component-based content architecture where sections are reusable across page types.
- The page building experience — editor plus live preview — is important for your content team.
Use fixed fields instead when:
- Every page of the same type has an identical structure. A simple "About" page with a fixed set of fields doesn't benefit from dynamic blocks.
- The content is short and predictable. A contact page with an address, phone number, and map doesn't need composable sections.
- Editors shouldn't have layout control. Some page types should look the same across all instances, and fixed fields enforce that.
Many page models use both. Fixed fields at the top for metadata, title, and hero content, with a dynamic block field for the composable body area below. This gives you a consistent page header with a flexible content area.
Dynamic Blocks in the Content API
When consuming dynamic blocks through the API, the field returns an array of block objects. Each object includes a _type identifier corresponding to the block model handle and the block's field data.
const page = client.getPage('/');
// page.sections → [
// { _type: 'hero', heading: 'Welcome', subheading: '...', image: { url: '...' } },
// { _type: 'features', heading: 'Why Us', items: [...] },
// { _type: 'cta', heading: 'Get Started', button_label: 'Sign Up', button_url: '/signup' }
// ]
Your frontend iterates over the sections array and renders the appropriate component for each block type. Hidden blocks are excluded from the API response — only visible sections are delivered.
The order of the array matches the order editors set in the editor. If an editor moves the CTA block above the features block, the API response reflects that order. Your frontend renders the array in sequence to produce the same layout the editor composed.
→ Content API → @sleekcms/client
What's Next
- Block Models — Defining the block types that editors compose pages from.
- Block Fields — Using a single block field vs a dynamic block field.
- Content Field Types — The full set of field types available in models.
- Page Models — How dynamic block fields fit into page model design.
- Site Builder — The integrated coding environment where block templates are built.
- Model Templates — Binding EJS templates to block, page, and entry models.
- Content Editing — The full editing experience for content creators.