Domma CMS User Manual

Blocks

Updated by Darryl Waterhouse on 18 October 2026 7 min read

A block is a small piece of your own HTML, with an optional stylesheet, that you write once and place anywhere. Its placeholders are filled in when the page is drawn: from a collection's entries, from a view, or from values you type into the shortcode. Use a block when the built-in displays are not quite the design you want. Team cards, product tiles, testimonials, a price table row and a contact panel are all one block each, and the data behind them stays in a collection where anyone can edit it.

Blocks are kept in Data > Blocks. Each one is a file in content/blocks/: <name>.html holds the template, <name>.css its styles (optional) and <name>.meta.json its project and bundled flag (optional).

Three ways to place a block

You want Write Placeholders come from
One copy per collection entry [collection slug="team" display="block" block="team-card" cols="3" /] Each entry's fields
One copy per row of a view (filtered, joined, sorted) [view slug="open-jobs" display="block" block="job-card" /] Each row of the view
One copy by itself, with values you type [block template="cta-banner" heading="Book a call" /] or the short tag [cta-banner heading="Book a call" /] The shortcode's own attributes

A block also draws each slide of a carousel or each row of a list group: [collection slug="team" display="carousel" block="team-card" /] and display="listgroup" block="…" work the same way.


Blocks with collections and views

This is where blocks are most useful. The collection holds the data and the block holds the design, so a new entry shows up on the page, styled, as soon as it is saved. There is no page to edit.

  • display="block" plus block="<name>" draws every entry through the block.
  • On a [collection], cols="2" to cols="6" lays the copies out in a responsive grid. Leave it out to stack them. A [view] always stacks them.
  • Everything else on [collection] still works: limit, sort, order, the where_<field> filters, scope="mine", empty, item-class and the per-entry cta buttons (drawn under each copy).
  • On a [view], block="…" may be left out when the view's Display tab already names a block.
  • Visitors can still right-click any copy to filter, sort, group, copy or export, as they can on the other displays. Only the fields the block actually uses are offered.

If the named block does not exist, the page shows Block template "name" not found where the entries would be, so a typo is easy to spot.

Blocks on their own

[block template="name" … /] draws one copy, with each other attribute filling the placeholder of the same name. Every block can also be written with its name as the tag, so [contact-card full_name="Jane Doe" /] means the same as [block template="contact-card" full_name="Jane Doe" /].

  • Short tags are self-closing (end with /]). They work for any block whose name does not clash with a built-in shortcode. A block called card or menu can only be placed with [block template="…"].
  • class and id go on the wrapper around the copy.
  • A placeholder with no value comes out empty, and a block that does not exist is removed without a message.
  • Values are written in double quotes. For a value that itself contains a double quote, use single quotes around it instead.
  • Blocks are expanded even inside inline code and code fences on a page. To mention a block's shortcode in ordinary text, write its opening bracket as &#91;. Inside code that does not work (it shows as written), so keep block shortcodes out of code samples on your pages.

Writing the template

A template is ordinary HTML. Domma classes (card, badge, grid, btn) and icons (<span data-icon="mail"></span>) work as they do anywhere else on the site. Placeholders are field names in double curly braces:

Placeholder What goes in
{{field}} The value, made safe as text (HTML is escaped). Use this almost everywhere.
{{field:DD MMM YYYY}} The value formatted as a date. Tokens: YYYY YY MMMM MMM MM M DD D dddd ddd HH H hh h mm m ss s A a; anything else passes through, so DD/MM/YYYY and HH:mm work. A value that is not a date is shown as it is.
{{{field}}} The value inserted as HTML, unescaped. Only for fields you trust, such as rich text written by your own editors.
{{_id}}, {{_createdAt}}, {{_updatedAt}} The entry's id and its created and updated times (collections and views only). Combine them with a format: {{_createdAt:D MMMM YYYY}}.

The page is cleaned before it is sent, so anything in a block that could run code (a <script>, an onclick or onerror handler, a javascript: link) is removed, exactly as it would be in page content.

Describe the block in a comment

Start the template with an HTML comment saying what it is, what it expects and how to use it. The Blocks list shows the first line as the block's description, and Copy shortcode copies the example. Comments are stripped when the block is drawn, so they never reach the page.

<!--
  team-card - One team member: photo, name, role and a short bio.

  Parameters:
    name   - Full name
    role   - Job title
    photo  - Image URL
    bio    - One or two sentences

  Example:
    [collection slug="team" display="block" block="team-card" cols="3" /]
-->
<div class="card team-card">
  <img class="team-card-photo" src="{{photo}}" alt="{{name}}">
  <div class="card-body">
    <h3>{{name}}</h3>
    <span class="badge badge-secondary">{{role}}</span>
    <p>{{bio}}</p>
  </div>
</div>

Styles

A block's Custom CSS applies to that block only: the CMS wraps it in [data-block="name"] { … }, so plain rules like .team-card-photo { … } cannot leak onto the rest of the page. Use CSS nesting for child rules, and the theme's --dm-* variables (var(--dm-primary), var(--dm-border)) so the block follows the site theme and dark mode.

.team-card-photo {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-bottom: 3px solid var(--dm-primary);
}

@keyframes, @font-face and @import cannot be scoped. Put those in Site Settings > Custom CSS. A block's stylesheet may be up to 50 KB. It is sent once for each shortcode that uses the block, however many entries that shortcode shows.


The Blocks screen

Data > Blocks lists every block with its description, whether it has CSS, and how many pages and views use it.

  • All, In use and Unused filter the list, and the search box finds a block by name or description.
  • Click a block to edit it. Right-click it (or use ⋮, or Shift+F10) to copy its shortcode, see where it is used, duplicate, export or delete it.
  • New block and Import are in the banner at the top.
  • The sidebar badge counts your blocks. Hover over it for the unused ones and the latest changes.

In use is worked out from page sources and view settings. A Tool that draws a block from its own code is not counted, so check before deleting a block marked unused.

Editing a block

A block opens as a tab in the page editor's workspace, beside pages and components - from the Blocks list, from the list on the editor's left, or from a page's This page section (the blocks that page uses).

  • HTML and CSS: the two parts of the block, in the editor pane, with Format (tidies the indentation). The toolbar's three buttons - or Ctrl+\ - choose editor and preview, editor only or preview only.
  • Preview: the block drawn on the open page that uses it, outlined, with your changes as you type - or, when no open page uses it, on its own inside your site's page shell, with its theme, fonts and Custom CSS. Preview only has full, tablet and mobile widths.
  • The dock (the sliders button): Block - its short tag and shortcode, an optional project, Bundled (ships the block with fresh installs) and where it is used; Samples - one box per placeholder the template uses, filled in for the on-its-own preview only. Nothing in them is saved. Right-click one to insert its placeholder into the template.
  • New block: the + by Blocks in the editor's list, or New block in the Blocks banner - a name (lowercase letters, digits and hyphens, fixed once created), then its tab.

Ctrl+S saves the tab you are on; Save all saves every open page, block and component. A block used elsewhere changes there too - you are asked the first time. Closing a tab, or leaving with unsaved changes, keeps your work as a draft for that block until you open it again.

Copying blocks between sites

Export on a block's right-click menu downloads it as a <name>.dmblock.json file, with its HTML and CSS. On the other site, use Import in the Blocks banner. If a block with that name already exists, you are asked before it is replaced.


Worked example: a team page

  1. In Data > Collections, create a team collection with the fields name, role, photo and bio, and add a few people.
  2. In Data > Blocks, choose New block, call it team-card and paste the template and CSS from above. Fill in the sample values and check the preview at mobile width and as three in a grid. Save.
  3. On your Team page, write [collection slug="team" display="block" block="team-card" cols="3" sort="name" order="asc" /].
  4. From now on, adding a person to the collection adds a card to the page. Changing the block restyles every card at once.

Who can use Blocks

Blocks share the pages permission: read to see them, update to create, edit and import, and delete to remove them. A block filed under a project is only shown to users who can see that project.

Blocks in your own Tools

A Tool (plugin) can rely on blocks too. It can render one of its pages with a block shortcode, or create the block it needs the first time it is switched on, so the site owner can restyle it here. See Writing a Tool.

Full shortcode syntax: Shortcodes. Collection displays: Collections & Forms and Views.