Block reference

Every block's fields and canonical YAML examples

Blocks are entries in a YAML frontmatter blocks: array. This reference is generated from the full field schemas and canonical BLOCK_EXAMPLES, in deliberate registry order. Regenerate with npm run generate-references, or npm run generate-blocks-reference for this file alone.

See Layouts for rendering architecture, column matching, sidebar behavior, and styling. All source paths below are repository-root-relative.

Reading the schemas

Schema types retain authoring semantics: markdown, image, and reference store strings; array<T> is a list of T. Dotted paths describe nested objects, and [] describes each list item. A required child is required only when its optional parent object is supplied (or for each supplied list object). Required fields must be supplied even when a default is shown.

The Default column shows the value the build fills in when a block omits the field, after validation and before rendering, so templates and authors can rely on it. Defaults of nested fields apply within each supplied parent object. Derived defaults depend on another field, as the description explains; None means an omitted field stays absent. Descriptions and usage notes may describe contextual/template behavior beyond schema validation.

CMS collection availability describes the schema's editor allowlist, not a runtime restriction. Site CMS customization can hide collections or blocks. Contextual blocks may still need page data to render usefully. CMS label identifies editor-exposed fields; Not exposed fields can still be authored in YAML.

Common fields

type is a required string selecting a registered block. The common wrapper fields below come from CONTAINER_FIELDS. dark selects a dark section palette; compact reduces section padding. They affect full-width section wrappers, not direct column/sidebar rendering; transparent snippet blocks do not acquire their own wrapper.

Field Schema type Presence Default CMS label Description
dark boolean optional false Dark
compact boolean optional None Compact

Column and sidebar compatibility

This table covers registered types only. No types are rejected inside columns and the right-content sidebar, but may appear in full-width before slots. Yes means the type passes the placement check, not that it is context-free. Snippets are reusable compositions: keep their contents appropriate for their destination too.

Block Container width Columns / sidebar
section-header wide Yes
features wide Yes
image-cards wide Yes
stats wide Yes
code-block wide Yes
hero full No
split-image wide No
split-video wide No
split-code wide No
split-icon-links wide No
split-html wide No
split-callout wide No
split-full full No
cta wide Yes
callout narrow Yes
image-background full No
video-background full No
items wide Yes
items-array wide Yes
items-text-list wide Yes
link-columns wide Yes
markdown wide Yes
table-of-contents narrow Yes
html wide Yes
iframe-embed wide Yes
include wide Yes
news-meta wide Yes
faqs wide Yes
guide-categories wide Yes
guide-header full Yes
guide-navigation full Yes
guide-pages-list full Yes
link-button wide Yes
gallery wide Yes
marquee-images full No
video-cards wide Yes
reviews wide Yes
contact-form wide No
quote-form wide No
add-to-quote wide Yes
icon-links narrow Yes
downloads narrow Yes
snippet wide Yes

section-header

Standalone section header with rich text intro.

Schema: src/_lib/utils/block-schema/section-header.js

Component: block_section_header

Template: src/_includes/design-system/blocks/section-header.html

SCSS: src/css/design-system/_base.scss

HTML root: <div class="section-header prose">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
intro markdown required None Section Header Intro Rich text content rendered as markdown. Use headings and body text together.
align string optional "center" Not exposed Text alignment. `"center"` adds `.text-center`.
class string optional None Not exposed Extra CSS classes.

Canonical example

blocks:
  - type: section-header
    intro: >-
      ## Section headers introduce a page section


      Use one wherever a group of blocks needs a heading and a sentence of
      context.

features

Grid of feature cards with optional icons, names, and descriptions.

Schema: src/_lib/utils/block-schema/features.js

Component: block_features

Template: src/_includes/design-system/blocks/features.html

SCSS: src/css/design-system/_feature.scss

HTML root: <ul class="features" role="list"> containing <li><article class="feature"> items

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
items array<object> required None Features Feature objects. Each: `{icon, icon_label, name, description, style}`. Icon can be an Iconify ID (`"prefix:name"`), image path (`"/images/foo.svg"`), or raw HTML/emoji.
items[].icon string optional None Icon (Iconify ID or HTML entity)
items[].icon_label string optional None Icon Accessible Label
items[].name string required None Name
items[].description markdown optional None Description
items[].style string optional None Custom Style
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
reveal boolean optional true Not exposed Adds `data-reveal` to each feature.
center boolean optional false Centered If true, centers feature text.

Canonical example

blocks:
  - type: features
    intro_content: "## A grid of features"
    items:
      - icon: hugeicons:cube
        name: Composable
        description: Pages are YAML lists of typed blocks.
      - icon: hugeicons:shield-01
        name: Validated
        description: Unknown types or keys fail the build loudly.
      - icon: hugeicons:rocket
        name: Static
        description: Everything renders to plain HTML at build time.

image-cards

Grid of cards featuring images with names and optional descriptions.

Schema: src/_lib/utils/block-schema/image-cards.js

Component: block_image_cards

Template: src/_includes/design-system/blocks/image-cards.html

SCSS: src/css/design-system/_items.scss

HTML root: <ul class="items" role="list">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
items array<object> required None Cards Card objects. Each: `{image, name, description, link}`. Images processed by `{% image %}` shortcode for responsive srcset + LQIP.
items[].image image required None Image
items[].name string required None Name
items[].description string optional None Description
items[].link string optional None Link URL
reveal boolean optional true Not exposed Adds `data-reveal` to each card.
image_aspect_ratio string optional None Image Aspect Ratio Aspect ratio for images, e.g. `"16/9"`, `"1/1"`, `"4/3"`.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Canonical example

blocks:
  - type: image-cards
    items:
      - image: breakfast.jpg
        name: Breakfast
        description: Cards pair an image with a name and description.
        link: /how-it-works/
      - image: lunch.jpg
        name: Lunch
        description: Images get responsive srcset and LQIP placeholders.
      - image: dinner.jpg
        name: Dinner
        description: An optional link makes the whole card clickable.

stats

Key metrics displayed as large numbers with labels.

Schema: src/_lib/utils/block-schema/stats.js

Component: block_stats

Template: src/_includes/design-system/blocks/stats.html

SCSS: src/css/design-system/_stats.scss

HTML root: <dl class="stats">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
items array<object> required None Statistics Stat objects: `{value, label}` or pipe-delimited strings `"value|label"`. Also accepts "value|label" strings.
items[].value string required None Value
items[].label string required None Label
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
reveal boolean optional true Not exposed Adds `data-reveal` to each stat.

Canonical example

blocks:
  - type: stats
    items:
      - value: 35+
        label: Block types
      - value: 100%
        label: Line coverage
      - value: "0"
        label: Servers to run

code-block

Terminal-style code display with macOS-like toolbar header.

Schema: src/_lib/utils/block-schema/code-block.js

Component: block_code_block

Template: src/_includes/design-system/blocks/code-block.html

SCSS: src/css/design-system/_code-block.scss

HTML root: <div class="code-block">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
filename string required None Filename Displayed in the toolbar header.
code string required None Code Code content. Rendered in `<pre><code>`.
language string optional None Language Sets `data-language` attribute (for future syntax highlighting).
reveal boolean optional true Not exposed Adds `data-reveal` to the code block.

Canonical example

blocks:
  - type: code-block
    intro_content: "## Commands to get started"
    filename: quick-start.sh
    language: bash
    code: |-
      npm install
      npm run serve

hero

Full-width hero banner with optional badge, markdown content, and action buttons.

Schema: src/_lib/utils/block-schema/hero.js

Component: block_hero

Template: src/_includes/design-system/blocks/hero.html

SCSS: src/css/design-system/_hero.scss

HTML root: <header class="hero">

Container width: full

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
badge string optional None Badge Text Small pill label above the content. Renders as `<span class="badge">`.
content markdown required None Content Markdown content rendered in `.prose`. Start with a `# Heading`; paragraphs get `body-lg` size and muted color in a centered, guttered measure.
buttons array<object> optional None Buttons Action buttons below the content. Each: `{text, href, variant, size}`. Variants: `"primary"` (filled), `"secondary"` (outlined), `"ghost"` (transparent). Sizes: `"sm"`, `"lg"`, or omit for default.
buttons[].text string required None Button Text
buttons[].href string required None URL
buttons[].variant string optional "primary" Variant
buttons[].size string optional None Size
reveal string optional None Not exposed `data-reveal` value.
class string optional None CSS Class Extra CSS classes on the `<header>`. Use `"gradient"` for gradient bg.

Canonical example

blocks:
  - type: hero
    badge: Hero block
    content: >-
      # A full-width opening banner


      Start most pages with one of these: a heading, a sentence of context, and
      the actions that matter.
    buttons:
      - text: Primary action
        href: /how-it-works/
        variant: primary
        size: lg
      - text: Secondary
        href: /blocks/
        variant: secondary
        size: lg

split-image

Two-column layout with text content and a responsive image.

Schema: src/_lib/utils/block-schema/split-image.js

Component: block_split_image

Template: src/_includes/design-system/split.html

SCSS: src/css/design-system/_split.scss

HTML root: <div class="split">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
subtitle string optional None Subtitle Subtitle with `.text-muted` styling.
content markdown optional None Content Main content with markdown headings (e.g. `## Heading`). Rendered through `renderContent: "md"` filter, wrapped in `.prose`.
reverse boolean optional false Reverse Layout Reverses column order (content right, figure left) on desktop.
reveal_content string optional Derived Reveal Content Animation `data-reveal` for the text side. Defaults to `"left"`, or `"right"` when `reverse` is true.
reveal_figure string optional "scale" Reveal Figure Animation `data-reveal` for the figure side.
button object optional None Button `{text, href, variant, size}`. Rendered below content.
button.text string required None Button Text
button.href string required None URL
button.variant string optional "secondary" Variant
button.size string optional None Size
figure_src image required None Figure Image Image path.
figure_alt string optional None Figure Alt Text Alt text for the image.
figure_caption string optional None Figure Caption Visible caption below the image.

Canonical example

blocks:
  - type: split-image
    subtitle: Split layouts
    content: >-
      ## Text beside an image


      The figure sits on the right by default; set `reverse: true` to flip the
      columns.
    figure_src: fireworks.jpg
    figure_alt: Fireworks over a city at night
    figure_caption: Captions are optional.

split-video

Two-column layout with text content and an embedded video.

Schema: src/_lib/utils/block-schema/split-video.js

Component: block_split_video

Template: src/_includes/design-system/split.html

SCSS: src/css/design-system/_split.scss

HTML root: <div class="split">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
subtitle string optional None Subtitle Subtitle with `.text-muted` styling.
content markdown optional None Content Main content with markdown headings (e.g. `## Heading`). Rendered through `renderContent: "md"` filter, wrapped in `.prose`.
reverse boolean optional false Reverse Layout Reverses column order (content right, figure left) on desktop.
reveal_content string optional Derived Reveal Content Animation `data-reveal` for the text side. Defaults to `"left"`, or `"right"` when `reverse` is true.
reveal_figure string optional "scale" Reveal Figure Animation `data-reveal` for the figure side.
button object optional None Button `{text, href, variant, size}`. Rendered below content.
button.text string required None Button Text
button.href string required None URL
button.variant string optional "secondary" Variant
button.size string optional None Size
figure_video_id string required None Video ID or embed URL Bare YouTube video ID (e.g. `dQw4w9WgXcQ`), or the full embed URL of another provider (Vimeo, Bunny Stream). Never an `<iframe>` snippet.
figure_thumbnail_url string optional None Thumbnail Image path or URL shown behind the play button. Defaults to the provider's own thumbnail for a YouTube ID or a Vimeo URL; other providers show a plain panel.
figure_alt string optional "Video" Video Name Name of the video, used for the play button's label and the iframe's title.
figure_caption string optional None Video Caption Visible caption below the video.
figure_autoplay boolean optional false Autoplay If true, skips the play button and starts the video muted, with its controls showing, when it scrolls into view.

Usage notes: Without `figure_autoplay` the video loads only when its play button is pressed.

Canonical example

blocks:
  - type: split-video
    subtitle: Split layouts
    content: |-
      ## Text beside a video

      The video loads when a visitor presses play.
    figure_video_id: dQw4w9WgXcQ
    figure_thumbnail_url: dinner.jpg
    figure_alt: A YouTube video
    figure_caption: Captions are optional.

split-code

Two-column layout with text content and a code block.

Schema: src/_lib/utils/block-schema/split-code.js

Component: block_split_code

Template: src/_includes/design-system/split.html

SCSS: src/css/design-system/_split.scss

HTML root: <div class="split">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
subtitle string optional None Subtitle Subtitle with `.text-muted` styling.
content markdown optional None Content Main content with markdown headings (e.g. `## Heading`). Rendered through `renderContent: "md"` filter, wrapped in `.prose`.
reverse boolean optional false Reverse Layout Reverses column order (content right, figure left) on desktop.
reveal_content string optional Derived Reveal Content Animation `data-reveal` for the text side. Defaults to `"left"`, or `"right"` when `reverse` is true.
reveal_figure string optional "scale" Reveal Figure Animation `data-reveal` for the figure side.
button object optional None Button `{text, href, variant, size}`. Rendered below content.
button.text string required None Button Text
button.href string required None URL
button.variant string optional "secondary" Variant
button.size string optional None Size
figure_filename string optional None Code Filename Displayed filename in the code block header.
figure_code string required None Code Content Code content.
figure_language string optional None Code Language Syntax highlighting language.

Canonical example

blocks:
  - type: split-code
    subtitle: Split layouts
    content: >-
      ## Text beside a code block


      Use this to walk through configuration or commands next to the
      explanation.
    figure_filename: site.json
    figure_language: json
    figure_code: |-
      {
        "name": "My Site",
        "url": "https://example.com"
      }

Two-column layout with text content and an icon-links list.

Schema: src/_lib/utils/block-schema/split-icon-links.js

Component: block_split_icon_links

Template: src/_includes/design-system/split.html

SCSS: src/css/design-system/_split.scss

HTML root: <div class="split">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
subtitle string optional None Subtitle Subtitle with `.text-muted` styling.
content markdown optional None Content Main content with markdown headings (e.g. `## Heading`). Rendered through `renderContent: "md"` filter, wrapped in `.prose`.
reverse boolean optional false Reverse Layout Reverses column order (content right, figure left) on desktop.
reveal_content string optional Derived Reveal Content Animation `data-reveal` for the text side. Defaults to `"left"`, or `"right"` when `reverse` is true.
reveal_figure string optional "scale" Reveal Figure Animation `data-reveal` for the figure side.
button object optional None Button `{text, href, variant, size}`. Rendered below content.
button.text string required None Button Text
button.href string required None URL
button.variant string optional "secondary" Variant
button.size string optional None Size
figure_items array<object> required None Links Icon-link objects. Each: `{icon, text, url}`. `url` is optional. Icon can be an Iconify ID (`"prefix:name"`), image path, or raw HTML/emoji.
figure_items[].icon string required None Icon (Iconify ID or HTML entity)
figure_items[].text string required None Link Text
figure_items[].url string optional None URL

Canonical example

blocks:
  - type: split-icon-links
    subtitle: Split layouts
    content: |-
      ## Text beside a list of links

      Each link gets an icon.
    figure_items:
      - icon: hugeicons:book-02
        text: How it works
        url: /how-it-works/
      - icon: hugeicons:cube
        text: Blocks
        url: /blocks/
      - icon: hugeicons:search-01
        text: Search
        url: /search/

split-html

Two-column layout with text content and custom HTML.

Schema: src/_lib/utils/block-schema/split-html.js

Component: block_split_html

Template: src/_includes/design-system/split.html

SCSS: src/css/design-system/_split.scss

HTML root: <div class="split">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
subtitle string optional None Subtitle Subtitle with `.text-muted` styling.
content markdown optional None Content Main content with markdown headings (e.g. `## Heading`). Rendered through `renderContent: "md"` filter, wrapped in `.prose`.
reverse boolean optional false Reverse Layout Reverses column order (content right, figure left) on desktop.
reveal_content string optional Derived Reveal Content Animation `data-reveal` for the text side. Defaults to `"left"`, or `"right"` when `reverse` is true.
reveal_figure string optional "scale" Reveal Figure Animation `data-reveal` for the figure side.
button object optional None Button `{text, href, variant, size}`. Rendered below content.
button.text string required None Button Text
button.href string required None URL
button.variant string optional "secondary" Variant
button.size string optional None Size
figure_html markdown required None Figure HTML Content Raw HTML content for the figure side.

Canonical example

blocks:
  - type: split-html
    subtitle: Split layouts
    content: |-
      ## Text beside custom HTML

      The figure column renders whatever HTML you give it.
    figure_html: <p style="font-size:3rem;text-align:center">🎉</p>

split-callout

Two-column layout with text content and a styled callout box with icon, name, and subtitle.

Schema: src/_lib/utils/block-schema/split-callout.js

Component: block_split_callout

Template: src/_includes/design-system/blocks/split-callout.html

SCSS: src/css/design-system/_split-callout.scss

HTML root: <div class="split-callout">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
subtitle string optional None Subtitle Subtitle with `.text-muted` styling.
content markdown optional None Content Main content with markdown headings (e.g. `## Heading`). Rendered through `renderContent: "md"` filter, wrapped in `.prose`.
reverse boolean optional false Reverse Layout Reverses column order (content right, figure left) on desktop.
reveal_content string optional Derived Reveal Content Animation `data-reveal` for the text side. Defaults to `"left"`, or `"right"` when `reverse` is true.
reveal_figure string optional "scale" Reveal Figure Animation `data-reveal` for the figure side.
button object optional None Button `{text, href, variant, size}`. Rendered below content.
button.text string required None Button Text
button.href string required None URL
button.variant string optional "secondary" Variant
button.size string optional None Size
figure_icon string optional None Icon (Iconify ID, emoji, or path) Icon content: Iconify ID (`prefix:name`), emoji, or image path.
figure_name string required None Callout Name Bold heading text in the callout box.
figure_subtitle string optional None Callout Subtitle Supporting text below the name.
figure_variant string optional "primary" Callout Color Variant Color scheme: `"primary"`, `"secondary"`, `"gradient"`, or a custom CSS gradient string.

Canonical example

blocks:
  - type: split-callout
    subtitle: Split layouts
    content: |-
      ## Text beside a callout card

      Good for highlighting one key fact or contact route.
    figure_icon: hugeicons:call
    figure_name: Talk to a person
    figure_subtitle: Phone lines open 9-5, Monday to Friday.

split-full

Full-width two-panel layout with distinct background colors per side.

Schema: src/_lib/utils/block-schema/split-full.js

Component: block_split_full

Template: src/_includes/design-system/blocks/split-full.html

SCSS: src/css/design-system/_split.scss

HTML root: <div class="split-full">

Container width: full

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
variant string optional None Variant Color scheme: `"dark-left"`, `"dark-right"`, `"primary-left"`, `"primary-right"`.
left_content markdown optional None Left Content Left panel content with markdown headings (e.g. `## Heading`). Rendered as markdown via `.prose`.
left_button object optional None Left Button `{text, href, variant, size}`.
left_button.text string required None Button Text
left_button.href string required None URL
left_button.variant string optional "secondary" Variant
left_button.size string optional None Size
right_content markdown optional None Right Content Right panel content with markdown headings (e.g. `## Heading`). Rendered as markdown via `.prose`.
right_button object optional None Right Button `{text, href, variant, size}`.
right_button.text string required None Button Text
right_button.href string required None URL
right_button.variant string optional "secondary" Variant
right_button.size string optional None Size
reveal_left string optional None Reveal Left Animation `data-reveal` for left panel.
reveal_right string optional None Reveal Right Animation `data-reveal` for right panel.

Usage notes: Variants: `"dark-left"` / `"dark-right"` (dark bg + light text), `"primary-left"` / `"primary-right"` (`--color-link` bg + contrast text). Button colors automatically invert in dark/primary panels. The parent `<section>` has zero padding — panels handle their own padding.

Canonical example

blocks:
  - type: split-full
    variant: dark-left
    left_content: |-
      ## Two panels

      Each side takes its own content and button.
    left_button:
      text: Left action
      href: /how-it-works/
      variant: secondary
    right_content: |-
      ## Side by side

      Variants control which side is dark.
    right_button:
      text: Right action
      href: /blocks/

cta

Call-to-action banner with gradient background.

Schema: src/_lib/utils/block-schema/cta.js

Component: block_cta

Template: src/_includes/design-system/blocks/cta.html

SCSS: src/css/design-system/_cta.scss

HTML root: <aside class="cta">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
content markdown required None Content Markdown content with optional heading (e.g. `## Heading`). `body-lg`, 0.9 opacity, max-width `$width-narrow`.
button object optional None Button `{text, href, variant, size}`.
button.text string required None Button Text
button.href string required None URL
button.variant string optional "secondary" Variant
button.size string optional "lg" Size
reveal string optional None Not exposed `data-reveal` value.

Canonical example

blocks:
  - type: cta
    content: |-
      ## Ready to try it?

      A call-to-action closes the page with one clear next step.
    button:
      text: How it works
      href: /how-it-works/
      size: lg

callout

One-column callout/note with icon, name, and short content — for content warnings, advisories, tips, etc.

Schema: src/_lib/utils/block-schema/callout.js

Component: block_callout

Template: src/_includes/design-system/blocks/callout.html

SCSS: src/css/design-system/_callout.scss

HTML root: <aside class="callout">

Container width: narrow

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
variant string optional "info" Variant (info | warning | success | danger) Color scheme: `"info"`, `"warning"`, `"success"`, or `"danger"`.
icon string optional None Icon (Iconify ID, emoji, or path) Icon content: Iconify ID (`prefix:name`), emoji, or image path.
name string optional None Name Bold heading text.
content markdown required None Content Markdown content rendered via `renderContent: "md"` inside `.prose`.

Canonical example

blocks:
  - type: callout
    variant: info
    icon: hugeicons:information-circle
    name: Good to know
    content: Callouts hold short advisories, tips, and warnings. Four color variants
      are available.

image-background

Full-width image background with hero-style overlay content (badge, markdown content, buttons) and optional parallax.

Schema: src/_lib/utils/block-schema/image-background.js

Component: block_image_background

Template: src/_includes/design-system/blocks/image-background.html

SCSS: src/css/design-system/_image-background.scss

HTML root: <div class="image-background">

Container width: full

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
image image required None Background Image Image path.
image_alt string optional "Background image" Image Alt Text Alt text.
class string optional None CSS Class Extra CSS classes.
badge string optional None Badge Text Small pill label above the content. Renders as `<span class="badge">`.
content markdown optional None Content Markdown overlay content rendered in `.prose` inside the `<figcaption>`.
buttons array<object> optional None Buttons Action buttons below the content. Each: `{text, href, variant, size}`. Variants: `"primary"` (filled), `"secondary"` (outlined), `"ghost"` (transparent). Sizes: `"sm"`, `"lg"`, or omit for default.
buttons[].text string required None Button Text
buttons[].href string required None URL
buttons[].variant string optional "primary" Variant
buttons[].size string optional None Size
reveal string optional None Not exposed `data-reveal` value.
parallax boolean optional false Parallax Enables CSS `animation-timeline: scroll()` parallax effect.
tint boolean optional false Tint Applies a dark gradient overlay for text legibility over the background image.

Usage notes: Image processed via `{% image %}` at widths 2560/1920/1280/960/640, cropped to 16/9. Parallax uses `animation-timeline: scroll()` for native CSS scroll-driven translation.

Canonical example

blocks:
  - type: image-background
    image: city-traffic-night.jpg
    image_alt: City traffic at night
    tint: true
    badge: Image background
    content: |-
      # Content over a full-width image

      A tint keeps the text readable.

video-background

Full-width video playing silently behind hero-style overlay content (badge, markdown content, buttons).

Schema: src/_lib/utils/block-schema/video-background.js

Component: block_video_background

Template: src/_includes/design-system/blocks/video-background.html

SCSS: src/css/design-system/_video-background.scss

Container width: full

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
video_id string required None Video ID or embed URL Bare YouTube video ID (e.g. `dQw4w9WgXcQ`); the block builds the embed itself. For other providers (Vimeo, Bunny Stream), the full embed URL. Never an `<iframe>` snippet.
video_title string optional "Background video" Video Title Accessible `title` on the iframe.
thumbnail_url string optional None Thumbnail Image path or URL shown over the iframe while the video loads. Defaults to the provider's own thumbnail for a YouTube ID or a Vimeo URL; other providers show nothing until the video plays.
class string optional None CSS Class Extra CSS classes.
badge string optional None Badge Text Small pill label above the content. Renders as `<span class="badge">`.
content markdown optional None Content Markdown overlay content rendered in `.prose` inside the `<figcaption>`.
buttons array<object> optional None Buttons Action buttons below the content. Each: `{text, href, variant, size}`. Variants: `"primary"` (filled), `"secondary"` (outlined), `"ghost"` (transparent). Sizes: `"sm"`, `"lg"`, or omit for default.
buttons[].text string required None Button Text
buttons[].href string required None URL
buttons[].variant string optional "primary" Variant
buttons[].size string optional None Size
reveal string optional None Not exposed `data-reveal` value.

Usage notes: YouTube IDs become `youtube-nocookie.com` embeds that autoplay muted, loop, and hide their controls; the thumbnail fades out once the player reports it is playing. Vimeo URLs gain autoplay, loop, and mute. A Bunny Stream embed URL is used as written, so set its `autoplay`, `loop`, and `muted` parameters yourself; its thumbnail fades out when the player starts, through a small script loaded only on pages with a Bunny background. The video is decorative: put anything a visitor must know in the overlay content.

Canonical example

blocks:
  - type: video-background
    video_id: dQw4w9WgXcQ
    thumbnail_url: city-traffic-night.jpg
    badge: Video background
    content: |-
      # Content over a full-width video

      The thumbnail shows until the video is playing.

items

Displays an Eleventy collection as a card grid or horizontal slider.

Schema: src/_lib/utils/block-schema/items.js

Component: block_items

Template: src/_includes/design-system/blocks/items.html

SCSS: src/css/design-system/_items.scss

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
collection string required None Collection Name Name of an Eleventy collection (e.g. `"news"`, `"guideCategories"`).
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
horizontal boolean optional false Horizontal Slider If true, renders as a horizontal slider instead of a wrapping grid.
masonry boolean optional false Masonry Grid If true, renders as a masonry grid using uWrap for zero-reflow height prediction.
filter object optional None Filter Filter object: `{property, includes, equals}`. `property` is a dot-notation path (e.g. `"url"`, `"data.name"`). When the resolved value is an array, the operator runs against each element (per-element exact match for `equals`, per-element substring for `includes`). `includes` matches substring; `equals` matches exact value.
filter.property string optional None Property (e.g. url, data.name)
filter.includes string optional None Contains
filter.equals string optional None Equals
image_aspect_ratio string optional None Image Aspect Ratio Aspect ratio for images, e.g. `"16/9"`, `"1/1"`, `"4/3"`.

Canonical example

blocks:
  - type: items
    collection: news
    intro_content: |-
      ## A collection as cards

      This example renders the `news` collection.

items-array

Renders items from an explicit list of paths. The collection is inferred dynamically from each item's path. Directory paths (ending in `/` or with no `.md` extension) expand to every item in that directory.

Schema: src/_lib/utils/block-schema/items-array.js

Component: block_items_array

Template: src/_includes/design-system/blocks/items-array.html

SCSS: src/css/design-system/_items.scss

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
items array<string> optional None Items Array of path strings. Each entry may be a file path (e.g. `src/news/example.md`) or a directory path (e.g. `src/news` or `src/news/`), in which case every item in that directory is included in place.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
horizontal boolean optional false Horizontal Slider If true, renders as a horizontal slider instead of a wrapping grid.
masonry boolean optional false Masonry Grid If true, renders as a masonry grid using uWrap for zero-reflow height prediction.
filter object optional None Filter Filter object: `{property, includes, equals}`. `property` is a dot-notation path (e.g. `"url"`, `"data.name"`). When the resolved value is an array, the operator runs against each element (per-element exact match for `equals`, per-element substring for `includes`). `includes` matches substring; `equals` matches exact value.
filter.property string optional None Property (e.g. url, data.name)
filter.includes string optional None Contains
filter.equals string optional None Equals
image_aspect_ratio string optional None Image Aspect Ratio Aspect ratio for images, e.g. `"16/9"`, `"1/1"`, `"4/3"`.

Canonical example

blocks:
  - type: items-array
    items:
      - news
    intro_content: |-
      ## Hand-picked items

      List file paths, or a directory to include everything in it.

items-text-list

Renders a collection as a comma-separated inline list of links, with optional introductory markdown text prepended. Excludes the current page from the list.

Schema: src/_lib/utils/block-schema/items-text-list.js

Component: block_items_text_list

Template: src/_includes/design-system/blocks/items-text-list.html

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
collection string required None Collection Name Name of an Eleventy collection (e.g. `"services"`, `"events"`).
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Canonical example

blocks:
  - type: items-text-list
    collection: news
    intro_content: "Read our latest news posts:"

Renders a collection as a plain-text unordered list of links arranged in responsive CSS columns. Optionally strips matching text via a regex so repetitive prefixes/suffixes can be removed.

Schema: src/_lib/utils/block-schema/link-columns.js

Component: block_link_columns

Template: src/_includes/design-system/blocks/link-columns.html

SCSS: src/css/design-system/_link-columns.scss

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
collection string required None Collection Name Name of an Eleventy collection (e.g. `"locations"`, `"services"`).
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
filter object optional None Filter Filter object: `{property, includes, equals}`. `property` is a dot-notation path (e.g. `"url"`, `"data.name"`). When the resolved value is an array, the operator runs against each element (per-element exact match for `equals`, per-element substring for `includes`). `includes` matches substring; `equals` matches exact value.
filter.property string optional None Property (e.g. url, data.name)
filter.includes string optional None Contains
filter.equals string optional None Equals
remove_text string optional None Remove Text (Regex) Regex pattern (JavaScript syntax, global flag implied). Each match is removed from every link's display text and the result is trimmed. Useful for stripping repetitive prefixes like `"Service in "` so links render tidier.

Canonical example

blocks:
  - type: link-columns
    collection: news
    intro_content: "## A collection as link columns"

markdown

Renders markdown content as rich text.

Schema: src/_lib/utils/block-schema/markdown.js

Component: block_markdown

Template: src/_includes/design-system/blocks/markdown.html

SCSS: src/css/design-system/_prose.scss

HTML root: <div class="prose">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
content markdown required None Markdown Markdown content. Passed through `renderContent: "md"` filter.

Canonical example

blocks:
  - type: markdown
    content: >-
      ## Plain markdown


      The simplest block: write markdown, get rich text. Lists, links, and
      **emphasis** all work.


      - One

      - Two

      - Three

table-of-contents

In-page contents built from the headings the page actually renders.

Schema: src/_lib/utils/block-schema/table-of-contents.js

Component: block_table_of_contents

Template: src/_includes/design-system/blocks/table-of-contents.html

SCSS: src/css/design-system/_table-of-contents.scss

HTML root: <nav class="table-of-contents">

Container width: narrow

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
title string optional "On this page" Title Heading above the list, and the accessible name of the navigation landmark.
levels string optional "2,3" Heading Levels Comma-separated heading levels to list, from `2` to `6`. Every other level is left out of the list, so `"2"` gives a top-level-only contents. An unlistable level fails the build.

Usage notes: The list is filled in after the page renders, from the headings in the page's main content at the levels this block names — no matter which blocks wrote them. Each listed heading gets an `id` (its own, when it already has one) so the links are stable, and the entries nest the way the headings do. A page whose headings none of the named levels match fails the build rather than publishing an empty contents.

Canonical example

blocks:
  - type: table-of-contents
    title: On this page
    levels: 2,3

html

Outputs raw HTML without processing.

Schema: src/_lib/utils/block-schema/html.js

Component: block_html

Template: src/_includes/design-system/blocks/html.html

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
content string required None Raw HTML Raw HTML. Output directly with `{{ block.content }}`.

Usage notes: No wrapping element. Useful for custom embeds, iframes, or one-off HTML.

Canonical example

blocks:
  - type: html
    content: <p><strong>Raw HTML</strong> passes straight through - the escape hatch
      for one-off markup.</p>

iframe-embed

Third-party iframe embed (itch.io widgets, Buttondown, Bandcamp, Stripe buttons, etc).

Schema: src/_lib/utils/block-schema/iframe-embed.js

Component: block_iframe_embed

Template: src/_includes/design-system/blocks/iframe-embed.html

SCSS: src/css/design-system/_iframe-embed.scss

HTML root: <div class="iframe-embed">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
src string required None Iframe URL Full URL of the iframe to embed.
name string required None Accessible Name Accessible name (rendered as the iframe's `title` attribute).
width number optional None Width (px) Fixed pixel width. Omit to fill the container.
height number optional None Height (px) Fixed pixel height. Required for non-responsive embeds unless `aspect_ratio` is set.
aspect_ratio string optional None Aspect Ratio (e.g. 16/9) CSS `aspect-ratio` for responsive height, e.g. `"16/9"`. Alternative to `height`.
max_width string optional None Max Width (CSS, e.g. 560px) CSS max-width on the wrapper, e.g. `"560px"`.
sandbox string optional None Sandbox Space-separated sandbox tokens, e.g. `"allow-scripts allow-same-origin allow-forms"`.
allow string optional None Allow (permissions policy) `allow` attribute for iframe permissions policy.
scrolling string optional None Scrolling Legacy `scrolling` attribute, e.g. `"no"`.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Usage notes: Provide either `height` for a fixed-height embed or `aspect_ratio` (e.g. `16/9`) for a responsive one. Use `max_width` to cap the embed width within the container.

Canonical example

blocks:
  - type: iframe-embed
    src: /search/
    name: The search page, embedded
    aspect_ratio: 16/9
    max_width: 560px

include

Includes an arbitrary template file.

Schema: src/_lib/utils/block-schema/include.js

Component: block_include

Template: src/_includes/design-system/blocks/include.html

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
file string required None Template File Path Path to the template file to include.

Usage notes: Escape hatch for custom content that doesn't fit the block system. The `file` value is passed straight to `{% include %}`.

Canonical example

blocks:
  - type: include
    file: demo-include.html

news-meta

Renders a news post's metadata: author name plus the post date.

Schema: src/_lib/utils/block-schema/news-meta.js

Component: block_news_meta

Template: src/_includes/design-system/blocks/news-meta.html

Container width: wide

CMS collection availability: news

Columns / sidebar: Yes

No block-specific fields. Common fields still apply.

Usage notes: News-only block. No parameters. Reads `author` from the page data and renders it as plain text, falling back to a date-only block when there is no author.

Canonical example

blocks:
  - type: news-meta

faqs

Renders question/answer pairs as a definition list, or as collapsed accordions with `collapsible: true`. Available on all page types.

Schema: src/_lib/utils/block-schema/faqs.js

Component: block_faqs

Template: src/_includes/design-system/blocks/faqs.html

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
items array<object> optional None FAQs FAQ question/answer pairs. Answers support markdown formatting. Falls back to page-level `faqs` array if omitted.
items[].question string required None Question
items[].answer markdown optional None Answer (Markdown)
collapsible boolean optional false Collapsible Collapse each answer under its question, opened by selecting the question (native details/summary, no JavaScript).
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Usage notes: Define FAQs inline via `items`, or omit to fall back to the page-level `faqs` array (useful for pages and guide pages that declare FAQs in frontmatter). Answers are rendered as markdown.

Canonical example

blocks:
  - type: faqs
    intro_content: "## Frequently asked questions"
    items:
      - question: How are FAQ answers formatted?
        answer: Answers support **markdown**, including links and lists.
      - question: Where else can FAQs come from?
        answer: Omit `items` and the block falls back to the page-level `faqs` array.

guide-categories

Displays the site-wide guide categories.

Schema: src/_lib/utils/block-schema/guide-categories.js

Component: block_guide_categories

Template: src/_includes/design-system/blocks/guide-categories.html

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

No block-specific fields. Common fields still apply.

Usage notes: No block-level parameters. Uses the global `collections.guide-categories`, minus any category with a `property`, which belongs to a single property's guide.

Canonical example

blocks:
  - type: guide-categories

guide-header

Renders a guide page's heading: title and optional subtitle.

Schema: src/_lib/utils/block-schema/guide-header.js

Component: block_guide_header

Template: src/_includes/design-system/blocks/guide-header.html

Container width: full

CMS collection availability: guide-pages, guide-categories

Columns / sidebar: Yes

No block-specific fields. Common fields still apply.

Usage notes: Guide-only block. No parameters. Reads `title` and `subtitle` from the page data.

Canonical example

blocks:
  - type: guide-header

guide-navigation

Renders a 'Back to <category>' breadcrumb link for a guide page.

Schema: src/_lib/utils/block-schema/guide-navigation.js

Component: block_guide_navigation

Template: src/_includes/design-system/blocks/guide-navigation.html

Container width: full

CMS collection availability: guide-pages

Columns / sidebar: Yes

No block-specific fields. Common fields still apply.

Usage notes: Guide-page-only block. No parameters. Renders nothing when the page has no `guide-category` field.

Canonical example

blocks:
  - type: guide-navigation

guide-pages-list

Lists the guide pages that belong to the current guide category (filtered via `guidesByCategory`).

Schema: src/_lib/utils/block-schema/guide-pages-list.js

Component: block_guide_pages_list

Template: src/_includes/design-system/blocks/guide-pages-list.html

Container width: full

CMS collection availability: guide-categories

Columns / sidebar: Yes

No block-specific fields. Common fields still apply.

Usage notes: Guide-category-only block. No parameters. A guide page with a `property` is only listed when the category carries the same `property`. Renders nothing when there are no pages left to show.

Canonical example

blocks:
  - type: guide-pages-list

Standalone centered button linking to an anchor or URL.

Schema: src/_lib/utils/block-schema/link-button.js

Component: block_link_button

Template: src/_includes/design-system/blocks/link-button.html

SCSS: src/css/design-system/_link-button.scss

HTML root: <div class="link-button">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
text string required None Button Text Button label.
href string required None URL Link URL or anchor (e.g. `"#contact"`, `"/about"`).
variant string optional "primary" Variant `"primary"`, `"secondary"`, or `"ghost"`.
size string optional None Size `"sm"`, `"lg"`, or omit for default.
reveal string optional None Reveal Animation `data-reveal` value.

Canonical example

blocks:
  - type: link-button
    text: A standalone button
    href: /search/
    variant: primary

Image grid with optional aspect ratio cropping and captions.

Schema: src/_lib/utils/block-schema/gallery.js

Component: block_gallery

Template: src/_includes/design-system/blocks/gallery.html

SCSS: src/css/design-system/_items.scss

HTML root: <ul class="items" role="list">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
items array<object> required None Gallery Images Image objects. Each: `{image, caption}`. Images processed by `{% image %}` shortcode.
items[].image image required None Image
items[].caption string optional None Caption
aspect_ratio string optional None Aspect Ratio Aspect ratio for images (e.g. `"16/9"`, `"1/1"`, `"4/3"`). Default: no cropping.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
masonry boolean optional false Masonry Grid If true, renders as a masonry grid using uWrap for zero-reflow height prediction.
horizontal boolean optional false Horizontal Slider If true, renders as a horizontal slider instead of a wrapping grid.

Canonical example

blocks:
  - type: gallery
    intro_content: "## An image grid"
    aspect_ratio: 4/3
    items:
      - image: breakfast.jpg
        caption: Breakfast
      - image: lunch.jpg
        caption: Lunch
      - image: dinner.jpg
        caption: Dinner
      - image: fireworks.jpg
        caption: Fireworks

marquee-images

Continuously scrolling marquee of images (e.g. brand logos, partner badges).

Schema: src/_lib/utils/block-schema/marquee-images.js

Component: block_marquee_images

Template: src/_includes/design-system/blocks/marquee-images.html

SCSS: src/css/design-system/_marquee-images.scss

HTML root: <div class="marquee-images">

Container width: full

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
items array<object> required None Images Image objects. Each: `{image, alt, link_url}`. `image` is a path; `alt` is optional alt text; `link_url` is an optional URL to wrap the image in a link. Images are processed via the `{% image %}` shortcode for responsive formats and proper URL normalization.
items[].image string required None Image Path
items[].alt string optional None Alt Text
items[].link_url string optional None Link URL
speed string optional "30s" Scroll Speed (e.g. 30s) CSS animation duration for one full scroll cycle (e.g. `"20s"`, `"45s"`). Slower = longer duration.
height string optional "50px" Image Height (e.g. 50px) CSS height for the images (e.g. `"60px"`, `"80px"`). Width scales proportionally.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Canonical example

blocks:
  - type: marquee-images
    height: 60px
    items:
      - image: breakfast.jpg
        alt: Breakfast
      - image: lunch.jpg
        alt: Lunch
      - image: dinner.jpg
        alt: Dinner
      - image: fireworks.jpg
        alt: Fireworks

video-cards

Grid of click-to-play video thumbnails. Takes YouTube IDs and the embed URLs of other providers (Vimeo, Bunny Stream).

Schema: src/_lib/utils/block-schema/video-cards.js

Component: block_video_cards

Template: src/_includes/design-system/blocks/video-cards.html

SCSS: src/css/design-system/_items.scss

HTML root: <ul class="items" role="list">

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
videos array<object> required None Videos Video objects. Each: `{id, name, thumbnail_url}`. `id` is a bare YouTube video ID (e.g. `dQw4w9WgXcQ`) or the full embed URL of another provider (Vimeo, Bunny Stream); never an `<iframe>` snippet. `thumbnail_url` is an image path or URL, and defaults to the provider's own thumbnail for a YouTube ID or a Vimeo URL.
videos[].id string required None Video ID or embed URL
videos[].name string required None Name
videos[].thumbnail_url string optional None Thumbnail
reveal boolean optional true Not exposed Adds `data-reveal` to each video.
expand boolean optional false Expand to Full Width If true, videos fill the available width (1 = 100%, 2 = 50%, 3+ = 33.3%) instead of the standard card grid.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Usage notes: A video loads only when its thumbnail is pressed, so the grid costs nothing until a visitor plays one. A YouTube or Vimeo thumbnail with no `thumbnail_url` is downloaded at build time, so a build with one needs the network; a video from another provider with no `thumbnail_url` shows a plain panel behind the play button.

Canonical example

blocks:
  - type: video-cards
    videos:
      - id: dQw4w9WgXcQ
        name: A YouTube video
        thumbnail_url: breakfast.jpg
      - id: https://player.vimeo.com/video/76979871
        name: A Vimeo video
        thumbnail_url: lunch.jpg
      - id: https://iframe.mediadelivery.net/embed/1/example
        name: A video with no thumbnail

reviews

Customer reviews as cards, newest first: rating, date, the reviewer's words, and a link to where they wrote it.

Schema: src/_lib/utils/block-schema/reviews.js

Component: block_reviews

Template: src/_includes/design-system/blocks/reviews.html

SCSS: src/css/design-system/_reviews.scss

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
minimum_rating number optional 1 Minimum Rating Only reviews rated at least this are shown, from `1` (every review) to `5`.
limit number optional None Limit Show at most this many reviews, newest first.
horizontal boolean optional false Horizontal Slider If true, renders as a horizontal slider instead of a wrapping grid.
masonry boolean optional false Masonry Grid If true, renders as a masonry grid using uWrap for zero-reflow height prediction.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Usage notes: Renders the `reviews` collection: one markdown file per review in `src/reviews/`, named `YYYY-MM-DD-reviewer.md`, with `name`, `rating`, and optional `source`, `url`, and `avatar` (the reviewer's photo; their initial shows without one) in the frontmatter and the review as the body. `npm run fetch-reviews` writes these files from Google, Facebook and Trustpilot. A review with `hidden: true` is left out. The block renders nothing when no review qualifies.

Canonical example

blocks:
  - type: reviews
    minimum_rating: 4
    limit: 6
    intro_content: "## What customers say"

contact-form

A contact form, optionally beside text, that posts to a form service.

Schema: src/_lib/utils/block-schema/contact-form.js

Component: block_contact_form

Template: src/_includes/design-system/blocks/contact-form.html

SCSS: src/css/design-system/_contact-form.scss

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
content markdown optional None Content Text shown beside the form, rendered as markdown. Without it the form takes the full width.
fields array<object> optional [{"name":"name","label":"Name","type":"text","required":true},{"name":"email","label":"Email","type":"email","required":true},{"name":"phone","label":"Phone","type":"tel","required":false},{"name":"message","label":"Message","type":"textarea","required":true,"rows":6}] Form Fields The form's fields, in order. Defaults to name, email, phone, and message.
fields[].label string required None Label
fields[].name string optional Derived Name Name the answer is submitted under. Defaults to the label.
fields[].type string optional "text" Type `textarea`, `select`, `radio`, `heading` (a sub-heading between fields, with `note` as its text), or any HTML input type such as `text`, `email`, `tel`, `date`, or `number`.
fields[].required boolean optional false Required
fields[].placeholder string optional None Placeholder
fields[].note string optional None Help Note
fields[].options array<string> optional None Options Choices of a `select` or `radio` field.
fields[].rows number optional 6 Rows Height of a `textarea`, in lines of text.
submit_text string optional "Send Enquiry" Submit Button Text
redirect string optional "/thank-you/" Redirect Page a visitor lands on after sending the form.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Usage notes: A static site cannot receive a form, so the block posts to the URL in the `contact_form_target` setting, or to [Formspark](formspark.io) when `formspark_id` is set; with neither it shows a notice in place of the form. Setting `botpoison_public_key` adds a [Botpoison](botpoison.com) spam challenge, which needs JavaScript. The submission emails are named after the site, and a field named `email` becomes their reply address on Formspark.

Canonical example

blocks:
  - type: contact-form
    content: |-
      ## Get in touch

      Tell us what you need and we will get back to you.
    fields:
      - label: Name
        name: name
        required: true
      - label: Email
        name: email
        type: email
        required: true
      - label: What do you need?
        name: service
        type: select
        options:
          - A new website
          - Help with an existing site
          - Something else
      - label: Message
        name: message
        type: textarea
        required: true

quote-form

The visitor's quote: the products they added, an estimated price, and a form that sends the request to a form service.

Schema: src/_lib/utils/block-schema/quote-form.js

Component: block_quote_form

Template: src/_includes/design-system/blocks/quote-form.html

SCSS: src/css/design-system/_quote.scss

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: No

Field Schema type Presence Default CMS label Description
content markdown optional None Content Text shown beside the form, rendered as markdown. Without it the form takes the full width.
fields array<object> optional [{"name":"name","label":"Name","type":"text","required":true},{"name":"email","label":"Email","type":"email","required":true},{"name":"phone","label":"Phone","type":"tel","required":false},{"name":"start_date","label":"Start date","type":"date","required":true},{"name":"end_date","label":"End date","type":"date","required":true},{"name":"message","label":"Anything else we should know?","type":"textarea","required":false,"rows":4}] Form Fields The form's fields, in order. Defaults to name, email, phone, start and end dates, and a message.
fields[].label string required None Label
fields[].name string optional Derived Name Name the answer is submitted under. Defaults to the label.
fields[].type string optional "text" Type `textarea`, `select`, `radio`, `heading` (a sub-heading between fields, with `note` as its text), or any HTML input type such as `text`, `email`, `tel`, `date`, or `number`.
fields[].required boolean optional false Required
fields[].placeholder string optional None Placeholder
fields[].note string optional None Help Note
fields[].options array<string> optional None Options Choices of a `select` or `radio` field.
fields[].rows number optional 6 Rows Height of a `textarea`, in lines of text.
submit_text string optional "Request a Quote" Submit Button Text
redirect string optional "/quote-sent/" Redirect Page a visitor lands on after sending the form.
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.

Usage notes: Products carry an add-to-quote button; this block lists what was added, kept in the visitor's browser, with a quantity for each and an estimated total. It posts like the `contact-form` block, to `contact_form_target` or Formspark, adding the items as `cart_items`, the total as `estimated_total`, and the number of hire days as `hire_days`. Hire products are priced by the days between the `start_date` and `end_date` fields, counting both ends; a stay with no matching option is priced TBC. The quote is cleared once it is sent. Prices are shown in the `currency` setting.

Canonical example

blocks:
  - type: quote-form
    content: |-
      ## Your quote

      Add products to see them here.

add-to-quote

An add-to-quote button for the product the page describes.

Schema: src/_lib/utils/block-schema/add-to-quote.js

Component: block_add_to_quote

Template: src/_includes/design-system/blocks/add-to-quote.html

SCSS: src/css/design-system/_quote.scss

Container width: wide

CMS collection availability: products

Columns / sidebar: Yes

No block-specific fields. Common fields still apply.

Usage notes: Product-only block. No parameters. A product with more than one option gets a choice of option beside the button; a hire product is added once and priced by the days the visitor asks for. Renders nothing on a page without `options`.

Canonical example

blocks:
  - type: add-to-quote

Vertical list of links with icons, rendered as a flex column stack.

Schema: src/_lib/utils/block-schema/icon-links.js

Component: block_icon_links

Template: src/_includes/design-system/blocks/icon-links.html

SCSS: src/css/design-system/_icon-links.scss

HTML root: <ul class="icon-links" role="list">

Container width: narrow

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
items array<object> required None Links Link objects. Each: `{icon, text, url}`. `url` is optional — items without it render as plain text. Icon can be an Iconify ID (`"prefix:name"`), image path, or raw HTML/emoji.
items[].icon string required None Icon (Iconify ID or HTML entity)
items[].text string required None Link Text
items[].url string optional None URL
reveal boolean optional true Not exposed Adds `data-reveal` to each link item.

Canonical example

blocks:
  - type: icon-links
    intro_content: "## Links with icons"
    items:
      - icon: hugeicons:book-02
        text: How it works
        url: /how-it-works/
      - icon: hugeicons:cube
        text: Browse the blocks
        url: /blocks/
      - icon: hugeicons:search-01
        text: Search the site
        url: /search/

downloads

List of downloadable files. Each item auto-detects its icon from the file extension and its size from the filesystem at build time.

Schema: src/_lib/utils/block-schema/downloads.js

Component: block_downloads

Template: src/_includes/design-system/blocks/downloads.html

SCSS: src/css/design-system/_downloads.scss

HTML root: <ul class="downloads" role="list">

Container width: narrow

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
intro_content markdown optional None Intro Content (Markdown) Markdown content rendered above the block in `.prose`.
items array<object> required None Downloads Download objects. Each: `{file, label}`. `file` is a site-relative URL path; `label` is the visible text.
items[].file string required None File Path (e.g. /files/guide.pdf)
items[].label string required None Label
reveal boolean optional true Not exposed Adds `data-reveal` to each download item.

Usage notes: The `file` path is resolved against `src/` (e.g. `/files/guide.pdf` reads from `src/files/guide.pdf`). Missing files cause a build error. Ensure the containing directory is configured as a passthrough-copy target so the file is also served to the browser.

Canonical example

blocks:
  - type: downloads
    intro_content: "## Files to download"
    items:
      - file: /files/template-overview.txt
        label: Template overview (TXT)

snippet

Renders blocks from a named snippet file, enabling reusable block compositions.

Schema: src/_lib/utils/block-schema/snippet.js

Component: block_snippet

Template: src/_includes/design-system/blocks/snippet.html

Container width: wide

CMS collection availability: All collections with a block editor

Columns / sidebar: Yes

Field Schema type Presence Default CMS label Description
reference reference required None Snippet Filename of the snippet (without `.md` extension) from `src/snippets/`. CMS options: {"collection":"snippets"}

Usage notes: The referenced snippet must exist in `src/snippets/` and have a `blocks` frontmatter array. The snippet block is transparent — it renders no wrapping section element, so each inner block renders its own section directly.

Canonical example

blocks:
  - type: snippet
    reference: demo