Canopy Block Settings
Learn about the setting types available for Canopy Block templates
Settings define the fields content editors fill in for each Canopy Block. You declare them in the settings array of a block template's config section, and their values are available in the template section through the settings variable.
All setting types share these attributes:
| Attribute | Description | Data Type |
|---|---|---|
name | The setting identifier, used to access the value in the template section | String |
type | One of the setting types documented below | String |
label (optional) | The field label shown in the Canopy editor. Generated from the name if omitted | String |
default (optional) | The value used until an editor provides one | Mixed |
help (optional) | A short hint shown as an info icon tooltip beside the field label. See Help and descriptions | String |
description (optional) | Helper text rendered underneath the input. See Help and descriptions | String |
tab (optional) | The editor tab the setting appears under. See Tabs and groups | String |
group (optional) | The collapsible group the setting appears in. See Tabs and groups | String |
Tabs and groups
Blocks with many settings can organize them so editors are not shown everything at once. Both attributes are optional and only affect the editing form — they change nothing about how you access values in the template section.
Give settings a tab to split the form into tabs. Tabs appear in the order they are first used, and any settings without a tab are gathered under a General tab. The form only shows tabs when at least one setting declares one.
Give consecutive settings a group to place them under a labelled divider. Groups are open by default, and editors can collapse them.
{
"title": "Hero",
"name": "hero",
"settings": [
{ "name": "title", "type": "text", "tab": "Content" },
{ "name": "description", "type": "textarea", "tab": "Content" },
{ "name": "background", "type": "color", "tab": "Style", "group": "Colors" },
{ "name": "text_color", "type": "color", "tab": "Style", "group": "Colors" },
{ "name": "custom_class", "type": "text", "tab": "Style", "group": "Advanced" }
]
}This config gives the block a Content tab with two fields, and a Style tab where the color settings sit under a Colors group and the class setting under an Advanced group.
Help and descriptions
Every setting type accepts two optional strings for guiding editors. Like tabs and groups, they only affect the editing form and change nothing about the value in the template section.
helpis a short hint shown as an info icon tooltip beside the field label.descriptionis muted helper text rendered underneath the input.
Use help for a quick clarification editors may not need every time, and description for guidance that should always be visible:
{
"name": "subtitle",
"type": "text",
"help": "Shown under the page title.",
"description": "Keep it under 80 characters so it fits on one line."
}Text
type: text
A single line of plain text. The value is a String, with "New text" as the built-in default.
| Attribute | Description | Data Type |
|---|---|---|
placeholder (optional) | Placeholder text shown in the input | String |
<p>{{ settings.subtitle }}</p>Textarea
type: textarea
Multiple lines of plain text. The value is a String, empty by default.
| Attribute | Description | Data Type |
|---|---|---|
placeholder (optional) | Placeholder text shown in the input | String |
Richtext
type: richtext
Formatted text edited with a rich text editor. The value is an HTML String, so output it with the raw filter:
| Attribute | Description | Data Type |
|---|---|---|
placeholder (optional) | Placeholder text shown in the input | String |
<div class="prose">{{ settings.body|raw }}</div>Select
type: select
A dropdown of predefined options. The value is the selected option's value as a String.
| Attribute | Description | Data Type |
|---|---|---|
options | An array of options, each with a value and an optional label | Array |
{
"name": "alignment",
"type": "select",
"options": [
{ "value": "left", "label": "Left" },
{ "value": "center", "label": "Center" },
{ "value": "right", "label": "Right" }
],
"default": "center"
}Radio
type: radio
A set of radio buttons. Works exactly like Select, with the same options attribute, but shows every option at once in the editor.
Checkbox
type: checkbox
A single on or off toggle. The value is a Boolean, false by default.
{% if settings.show_title %}
<h2>{{ settings.title }}</h2>
{% endif %}File
type: file
A file picked from the site's assets. The value is an object describing the file.
| Attribute | Description | Data Type |
|---|---|---|
accept (optional) | A MIME type filter for the picker, such as application/pdf | String |
| Value property | Description | Data Type |
|---|---|---|
path | The file URL | String |
name | The filename | String |
type | The file's MIME type | String |
size | The file size in bytes | Number |
{% if settings.brochure.path %}
<a href="{{ settings.brochure.path }}" download>{{ settings.brochure.name }}</a>
{% endif %}URL
type: url
A link with editable text and target. The value is an object.
| Attribute | Description | Data Type |
|---|---|---|
placeholder (optional) | Placeholder text shown in the input | String |
| Value property | Description | Data Type |
|---|---|---|
url | The link URL | String |
text | The link text | String |
target | The link target, _self or _blank | String |
<a href="{{ settings.cta.url }}" target="{{ settings.cta.target }}">{{ settings.cta.text }}</a>Date
type: date
A date picker. The value is a formatted date String.
| Attribute | Description | Data Type |
|---|---|---|
format (optional) | The date format to store and output. Defaults to Y-m-d | String |
Color
type: color
A color picker. The value is a hex color String, #000000 by default.
<section style="background-color: {{ settings.background }}">...</section>Heading
type: heading
A heading with editable text and an editable HTML element. The value is an object.
| Attribute | Description | Data Type |
|---|---|---|
elements (optional) | The elements editors can choose from, each with a value and an optional label. Defaults to h1 through h6 | Array |
| Value property | Description | Data Type |
|---|---|---|
value | The heading text | String |
element | The HTML element, such as h2 | String |
<{{ settings.heading.element }}>{{ settings.heading.value }}</{{ settings.heading.element }}>Number
type: number
A numeric input. The value is a Number.
| Attribute | Description | Data Type |
|---|---|---|
min (optional) | The minimum allowed value | Number |
max (optional) | The maximum allowed value | Number |
placeholder (optional) | Placeholder text shown in the input | String |
List
type: list
A repeatable list of text items. The value is an Array of Strings, empty by default.
<ul>
{% for item in settings.features %}
<li>{{ item }}</li>
{% endfor %}
</ul>Media Sources
type: media-sources
A list of media files for HTML5 audio and video elements. The value is an Array of objects, each with a url and a type (the MIME type).
| Attribute | Description | Data Type |
|---|---|---|
placeholder (optional) | Placeholder text shown in the input | String |
<video controls>
{% for source in settings.video_sources %}
<source src="{{ source.url }}" type="{{ source.type }}" />
{% endfor %}
</video>Collection
type: collection
A collection picked from the site's collections. Use it when a block renders whatever a collection holds, and the editor decides which collection feeds it, such as a block that shows the latest items from any collection they choose. The editor sees a dropdown of the site's collections.
Collection settings use only the base attributes. default may be a collection handle String, and placeholder sets the dropdown's placeholder text.
| Attribute | Description | Data Type |
|---|---|---|
placeholder (optional) | Placeholder text shown in the dropdown | String |
The value is null while no collection is selected, or when the selected collection has been deleted. Otherwise it is an object:
| Value property | Description | Data Type |
|---|---|---|
id | The collection's unique id | String |
object | Always collection | String |
name | The collection name | String |
handle | The collection handle | String |
entries | The collection's entries | Array |
Each entry in entries exposes its field values under their field names, such as entry.title or entry.image, along with id, created_at, and updated_at.
{
"name": "source",
"type": "collection",
"label": "Collection",
"help": "All entries of the chosen collection are rendered."
}Always check the value before using it. A collection that was never selected, or was deleted after being selected,
resolves to null rather than erroring, so an unguarded template renders blank fields.
Entry
type: entry
One or more entries hand-picked from a collection. Use it when the editor chooses specific content rather than a whole collection: a featured item, a set of related items, or a hand-picked gallery.
| Attribute | Description | Data Type |
|---|---|---|
collection (optional) | Hard-declares the source collection by handle. The editor's collection dropdown is hidden and only this collection's entries can be picked. At render time this always wins over stored data | String |
default_collection (optional) | Pre-selects a collection in the editor, but the editor can switch to another. Switching clears the picked entries. Ignored when collection is set | String |
multiple (optional) | Whether editors pick a single entry or several. false shows a single entry dropdown, true a multi-select with add and remove. Defaults to false | Boolean |
min / max (optional) | Bounds for the number of entries when multiple is true. The editor enforces max | Number |
display_field (optional) | The entry field(s) shown as the label while picking. Accepts a single field name or an array of field names. Defaults to the entry's first non-empty text field | String or Array |
placeholder (optional) | Placeholder text shown in the entry dropdown | String |
Use collection whenever the block is designed around one specific collection. It gives editors a simpler picker
with no collection dropdown, and it guarantees the template's assumptions about which entry fields are available.
display_field only changes the labels in the editor's picker. It never affects what the template receives or renders.
Pass an array to show multiple values while picking: the first listed field with a value becomes the label, the remaining values appear alongside it, and searching matches all of the listed fields. This is useful when one field alone doesn't identify an entry, like products that share a name but differ by SKU:
{
"name": "featured",
"type": "entry",
"collection": "products",
"display_field": ["name", "sku"]
}Rendering entries
Each entry exposes its field values under their field names, along with id, created_at, and updated_at, just like the entries of a Collection setting.
With multiple off, the value is the picked entry, or null when nothing is picked or the entry or its collection was deleted:
{% if settings.featured %}
<h3>{{ settings.featured.title }}</h3>
<img src="{{ settings.featured.image }}" alt="{{ settings.featured.title }}">
{% endif %}With multiple on, the value is an array of entries in the exact order the editor picked them, so you can rely on that order for layout. Deleted entries are skipped, and the array is empty when nothing is picked:
{% if settings.related|length > 0 %}
{% for item in settings.related %}
{{ item.title }}
{% endfor %}
{% endif %}As with collections, guard your output: check single entries with if, and check arrays with the length filter.
Deleted content resolves to null or an empty array rather than erroring.
Common configurations
Lock the setting to one collection, and label entries by a specific field while picking:
{
"name": "featured",
"type": "entry",
"label": "Featured product",
"collection": "products",
"display_field": "sku"
}Pre-select a collection but let the editor switch to another:
{
"name": "highlight",
"type": "entry",
"label": "Highlight",
"default_collection": "products"
}Let the editor pick up to four entries:
{
"name": "related",
"type": "entry",
"label": "Related items",
"collection": "products",
"multiple": true,
"max": 4
}Entries and collections are stored by collection handle and entry id. Renaming a collection's handle breaks existing block data that points at it, so settle on handles before editors start filling in blocks.
Form
type: form
A form picked from the project's forms. It works like the Collection selector: the editor sees a dropdown of the project's forms and chooses one, so a single block template can render whichever form the page needs, a contact form here, a newsletter signup there, without hard-coding a handle.
| Attribute | Description | Data Type |
|---|---|---|
placeholder (optional) | Placeholder text shown in the dropdown | String |
default may be a form handle String.
The value is null while no form is selected, or when the selected form has been deleted. Otherwise it is an object:
| Value property | Description | Data Type |
|---|---|---|
object | Always form | String |
name | The form name | String |
handle | The form handle | String |
fields | The form's fields keyed by field name, in the same shape as the form tag's form.fields | Object |
Combine the setting with the form tag, passing the picked handle to the tag and looping the fields, and the block generates a fully working form for whichever form the editor selects:
{
"name": "contact_form",
"type": "form",
"label": "Form",
"placeholder": "Select a form"
}As with collections and entries, guard your output: a form that was never selected, or was deleted after being
selected, resolves to null rather than erroring.
Blog
type: blog
A blog picked from the site's blogs. It mirrors the Collection selector: the editor sees a dropdown of the site's blogs and chooses one, so a single block template can render posts from whichever blog the page needs, the news blog here, a case studies blog there, without hard-coding a slug.
| Attribute | Description | Data Type |
|---|---|---|
placeholder (optional) | The text on the empty option in the picker | String |
The stored value is the blog slug, a plain String, so default may be a blog slug too.
{ "name": "source", "type": "blog", "label": "Blog", "placeholder": "Choose a blog" }The value in the template section is null while no blog is picked, or when the slug no longer exists. Otherwise it is an object in the same shape the blog module returns, so existing blog markup ports over unchanged:
| Value property | Description | Data Type |
|---|---|---|
id | The blog's unique id | String |
object | Always blog | String |
name | The blog name | String |
slug | The blog slug | String |
description | The blog description | String |
uri | The blog's URI, such as /news | String |
layout | The blog's index layout template | String |
posts | The blog's published posts, newest first | Array |
posts_count | The number of published posts | Number |
posts_layout | The blog's post layout template | String |
{% if settings.source %}
<h2>{{ settings.source.name }}</h2>
{% for post in settings.source.posts %}
<article>
<a href="{{ post.slug }}">{{ post.title }}</a>
<p>{{ post.publish_date|date('d M Y') }}</p>
<p>{{ post.description }}</p>
</article>
{% endfor %}
{% endif %}The post object
Every post, whether it arrives through a blog's posts array or through a Post setting, exposes the same keys:
| Value property | Description | Data Type |
|---|---|---|
id | The post's unique id | String |
blog_id | The id of the blog the post belongs to | String |
title | The post title | String |
description | The post description | String |
content | The post body as HTML, output it with raw | String |
slug | The post's full path, such as /news/my-post | String |
author | The post author | String |
cover_image | The cover image URL | String |
seo_title | The SEO title | String |
seo_description | The SEO description | String |
is_noindex | Whether the post is excluded from indexing | Boolean |
is_nofollow | Whether the post's links are marked nofollow | Boolean |
publish_date | When the post publishes | String |
created_at | When the post was created | String |
updated_at | When the post was last updated | String |
slug is the post's full path, so link to it directly rather than prefixing the blog's uri. The three dates are Strings, ready to pass to the date filter.
Posts come back newest first, ordered by publish_date, both in a blog's posts array and in the editor's post picker.
As with collections and forms, guard your output: a blog that was never picked, or whose slug no longer exists,
resolves to null rather than erroring. Blogs are stored by slug, so renaming a blog's slug breaks existing block
data that points at it.
Post
type: post
One or more posts hand-picked from a blog. It mirrors the Entry setting: use it when the editor chooses specific posts rather than a whole blog, a featured post, a set of related reading, or a hand-picked roundup.
| Attribute | Description | Data Type |
|---|---|---|
blog (optional) | Locks the block to one blog by slug. The editor's blog dropdown is hidden, and this always overrides the stored slug | String |
default_blog (optional) | Pre-selects a blog in the editor, but the editor can change it. Ignored when blog is set | String |
multiple (optional) | Whether editors pick a single post or several. true switches to a multi-select. Defaults to false | Boolean |
max (optional) | Caps the number of selections when multiple is true | Number |
min (optional) | Accepted and validated, but not enforced by the picker, the same as Entry today | Number |
placeholder (optional) | The trigger text shown before anything is picked | String |
The stored value is { "blog": "<slug>", "id": <id> }, or { "blog": "<slug>", "ids": [<id>, ...] } in multiple mode.
{ "name": "featured", "type": "post", "label": "Featured post", "blog": "news" }{ "name": "related", "type": "post", "label": "Related", "multiple": true, "max": 3 }Use blog whenever the block is designed around one specific blog. It gives editors a simpler picker with no blog
dropdown, and it guarantees which posts the template can receive.
Rendering posts
Each post is a post object. With multiple off, the value is the picked post, or null when nothing is picked:
{% if settings.featured %}
<h3><a href="{{ settings.featured.slug }}">{{ settings.featured.title }}</a></h3>
<img src="{{ settings.featured.cover_image }}" alt="{{ settings.featured.title }}">
{% endif %}With multiple on, the value is always an array, empty rather than null when nothing is picked, in the exact order the editor picked them, so you can rely on that order for layout:
{% if settings.related|length > 0 %}
{% for post in settings.related %}
<a href="{{ post.slug }}">{{ post.title }}</a>
{% endfor %}
{% endif %}Picking posts
Picker labels are automatic: the post title, with the publish date as a muted hint beside it. There is no display_field equivalent, Entry needs one because collections have arbitrary fields, while posts always have a title.
Scheduled posts behave differently in the editor and on the site. The picker lists posts with a future
publish_date so editors can line them up ahead of time, but rendering excludes them, matching the blog module. A
scheduled post resolves to null, or drops out of the array in multiple mode, until it publishes. Always guard
your output.
Last updated on