Canopy Blocks
Learn how to build block templates that content editors can add, arrange, and edit in the Canopy editor
Canopy Blocks let you build entire sections of a page as reusable templates. You define a block template once in your project, and content editors can then add it to a page, fill in its settings, and arrange it alongside other blocks in the Canopy editor. This keeps a clear separation between code and content: developers decide what a section can look like, and editors compose pages from those sections.
Blocks are rendered in block areas. An area is scoped to the page it appears on by default, or shared across the whole site, so you can use the same approach for page content and for global sections like footers.
Create a block template
Block templates live in the canopy folder inside your project's views directory. Each template is a single .canvas file, and the filename becomes the template's name unless you set one in its config.
views/
└── canopy/
└── hero.canvasA block template is made up of named sections wrapped in {% canopy %} and {% endcanopy %} tags. Create hero.canvas with the following code:
{% canopy config %}
{
"title": "Hero",
"name": "hero",
"settings": [
{ "name": "heading", "type": "heading", "default": { "value": "Welcome to our site", "element": "h1" } },
{ "name": "description", "type": "textarea", "placeholder": "Add a short introduction..." },
{ "name": "cta", "type": "url", "label": "Call to action" }
]
}
{% endcanopy %}
{% canopy template %}
<section class="mx-auto max-w-7xl px-6 py-20">
<{{ settings.heading.element }}>{{ settings.heading.value }}</{{ settings.heading.element }}>
<p>{{ settings.description }}</p>
{% if settings.cta.url %}
<a href="{{ settings.cta.url }}" target="{{ settings.cta.target }}">{{ settings.cta.text }}</a>
{% endif %}
</section>
{% endcanopy %}A block template supports four sections, which can appear in any order:
| Section | Description |
|---|---|
config | A JSON object describing the block and the settings editors can change |
template | The Canvas code rendered for each block. This section is required |
head | Optional markup added to the page head when the block is used |
scripts | Optional markup added to the end of the page when the block is used |
The config section
The config section is a JSON object with the following properties:
| Property | Description | Data Type |
|---|---|---|
title | The name of the block shown to editors in the Canopy editor | String |
name (optional) | The unique identifier for the block template. Generated from the title if omitted | String |
settings (optional) | An array of settings editors can change for each block | Array |
hidden (optional) | Set to true to keep the block out of pickers. See Hidden blocks | Boolean |
children (optional) | Rules for the block's child blocks. See Canopy Nested Blocks | Object |
The children object accepts four optional sub-keys, documented in detail on the Canopy Nested Blocks page:
| Property | Description | Data Type |
|---|---|---|
children.allow | The templates editors can add as children. Replaces the folder set | Array |
children.min | Reserved for a minimum child count. Not yet enforced | Number |
children.max | The maximum number of children | Number |
children.default | Children a freshly added parent starts with | Array |
Every setting requires a name and a type. Most types also accept a label, a default, and a few type-specific attributes. Settings can also declare a tab and a group to organize the editing form into tabs and collapsible groups. See Canopy Block Settings for the full list of setting types and Tabs and groups for organizing them.
The config section must be valid JSON: keys and string values use double quotes, and trailing commas are not
allowed. Settings with a missing name, a missing type, or an unknown type are ignored.
Hidden blocks
Set hidden to true to keep a block template out of the Add Block picker:
{ "title": "Badge", "name": "badge", "hidden": true, "settings": [...] }A hidden block never appears in pickers unless a block area's allow list names it explicitly. Use it for special-purpose blocks — a badge that only belongs in the sidebar, a banner reserved for one area — that shouldn't clutter the general picker.
The template section
The template section is regular Canvas code. It receives a settings variable containing the values for the block, with the editor's content merged over the defaults from your config. Each setting is available under its name:
<p>{{ settings.description }}</p>The shape of each value depends on the setting type. Text settings give you a string, while settings like url, file, and heading give you an object with multiple properties. The Canopy Block Settings reference documents the value for every type.
Add styles and scripts
If a block needs its own CSS or JavaScript, put it in the head and scripts sections of the template:
{% canopy head %}
<link rel="stylesheet" href="/css/hero.css" />
{% endcanopy %}
{% canopy scripts %}
<script src="/js/hero.js"></script>
{% endcanopy %}These sections are output wherever your layout calls canopy.head and canopy.scripts. Each template's head and scripts are included once per area, no matter how many blocks use the same template.
Render blocks in your layout
Use the canopy.blocks function to output a block area in a layout or page:
<!DOCTYPE html>
<html>
<head>
<title>My Site</title>
{{ canopy.head('main') }}
</head>
<body>
{{ canopy.blocks('main') }}
{{ canopy.blocks('footer', { shared: true }) }}
{{ canopy.scripts('main') }}
</body>
</html>This code:
- Renders the blocks editors have added to the
mainarea of the current page, in the order they arranged them. - Renders a site-wide
footerarea. Thesharedoption means the same footer blocks appear on every page that renders the area. - Outputs the head and scripts sections for the blocks used in the
mainarea.
By default a block area is scoped to the current page, so the main area on your homepage and the main area on your about page hold different blocks.
Block areas also accept options to restrict the templates they accept (allow), cap the number of blocks (limit), and fix their structure (locked). See the canopy.blocks reference for all of them.
You can also render block templates directly, without editor content, using canopy.render:
{{ canopy.render('hero', { description: 'A custom description' }) }}Edit blocks in the dashboard
Once your layout renders a block area, open the page in the Canopy editor from the dashboard. Every block template in your views/canopy folder is available to add, and editors can fill in each block's settings and drag blocks into order without touching code.
Available functions
Blutui provides the following functions for working with Canopy Blocks:
canopy.blocksrenders a block areacanopy.renderrenders a block template directlycanopy.headoutputs the head sections for a block areacanopy.scriptsoutputs the scripts sections for a block area
Inside a parent block's template section, three more functions render its child blocks — see Canopy Nested Blocks:
canopy.childrenrenders the block's childrencanopy.childrenders a single child by positioncanopy.childListreturns the children for a custom loop
Last updated on