Skip to content

Toolbar

Every Section carries a floating, contextual toolbar that appears the instant a Section is selected (or hovered) and sits anchored above it. It's the primary way you shape a page's structure: width, height, columns, gaps, alignment, and section-level settings, all without opening a form. It's a different surface from the Style panel: the toolbar shapes the band and its layout, Style shapes background, spacing, and typography.

Floating section toolbar with Width, Height, Layout, and Style chips over a selected three-column Section, with the Review panel open in the right-hand sidebar

The toolbar over a selected Section, with the Review panel's live summary alongside it.

Choosing a starting layout

A freshly added Section has no columns yet. Selecting it (or clicking the + on a blank page) surfaces an in-canvas layout picker: Single, 2 Equal, 3 Equal, two asymmetric splits (Content + sidebar, Sidebar + content), and All layouts for the full gallery (including any section templates an admin has defined). Pick one to start; every value it sets can be changed later from the toolbar itself.

In-canvas layout chooser overlay (Single, 2 Equal, 3 Equal, two asymmetric splits, and All layouts) over the empty page's "Place items here" placeholder

The chips

Reading left to right: minimize (collapses the bar to a small pill; click it again to re-expand), move up / move down (reorders this Section among its siblings), a viewport chip (switches which breakpoint every per-viewport control below reads and writes, the same device set as the Style panel's picker), then the settings chips below, and finally ⋯ More.

Width, Height, and Layout are always present. Spacing and Arrange live inside the Layout popover rather than as their own chips, and Layout's Arrange sub-tab only appears once there's something to arrange (a single column still shows Spacing, since Gap spaces stacked content within one column too).

Width

Width popover listing Narrow, Contained (checked), Full width, and Breakout, each with a one-line description

  • Narrow: tighter than the default content width.
  • Contained: the default centered content width.
  • Full width: spans the full viewport.
  • Breakout: full-bleed background with boxed content, for a photo or color band that should touch both edges while text inside stays readable.

Width is intentionally not per viewport: one band width applies across all breakpoints.

Height

Height popover with Auto, Full height (checked), and Custom height rows, each with a one-line description

  • Auto: grows with its content (the default).
  • Full height: fills the viewport height.
  • Custom height: reveals a Min height ↔ Fixed toggle plus a value + unit field (px, %, vh, dvh). Min height sets a floor the content can still grow past; Fixed pins an exact height and content may overflow it.

Height is also not per viewport. The section also carries an internal full_height boolean prop, which the toolbar always keeps in sync with height, clearing it on any Height pick, so the two can never disagree.

Layout: Structure / Arrange / Spacing

A single popover with up to three tabs, all keyed to the active viewport (count, layout preset, gap, align, and column order are per-viewport families, a mobile-first cascade like every other responsive value in this module).

Structure:

Layout popover's Structure tab: Layout Columns/Grid toggle, column count buttons 1–4 plus Auto, and layout-preset cards (Equal, 50/25/25, 25/50/25, 25/25/50, Advanced)

  • Display mode: Columns (a fixed count, side by side) or Grid (auto-fits items to a minimum width, wrapping as needed).
  • Column count: 1 up to the configured maximum (layout_defaults.columns.max_count and its per-viewport vp_max_* caps, admin-configurable), or Auto.
  • Layout preset: how width splits across columns (Equal, 50/25/25, …). Hidden once count is 1 or Auto. More layouts opens the same gallery as the empty-state chooser above, with every built-in and admin-defined template.
  • Min column width (Grid, or Columns + Auto): the width a column must keep before the row wraps to fewer columns.

Arrange:

Layout popover's Arrange tab: Vertical align (Top/Center/Bottom), a Stretch vertically toggle, Horizontal align (Start/Center/End), and a Column order Normal/Reversed toggle

  • Vertical align — Top / Center / Bottom, how columns sit within their row when it's taller than their content. Reachable even at a single visual column (a full-height section with one column still has a cross-axis to align along).
  • Stretch vertically — a toggle, not a fourth align option: on, the column fills the row's full height and Vertical align has nothing left to pick, so its row disables; off, Vertical align resumes from wherever it last sat.
  • Horizontal align — Start / Center / End, position within the row. Disables (with a note) whenever Distribution on the Spacing tab isn't Normal — both write the same underlying field, one value at a time.
  • Column order — visually reverses the Section's physical Column children (e.g. image-first on desktop, text-first on mobile) without touching source/reading order for assistive tech.

Spacing:

Layout popover's Spacing tab: five gap tiles from None to X-Large, Medium selected, and a Distribution row (Normal/Between/Evenly)

  • Gap spaces both the columns from each other and components stacked inside a single column (.cb-col-slot), so it stays reachable at any column count.
  • Distribution — Normal / Between / Evenly. This and Horizontal align (Arrange tab) are two views onto the same field: picking Between or Evenly here is what disables Horizontal align there, and picking Normal restores whichever Start/Center/End position was last set. Not shown in Grid mode.

Backing fields reference

Control Backing field
Layout → Arrange → Vertical align / Stretch valign (Columns) or grid_valign (Grid) — Stretch is valign: stretch, not a separate field
Layout → Arrange → Horizontal align halign (Columns only), written only as start/center/end from this control
Layout → Arrange → Horizontal align (Grid) grid_halign — a single unchanged Stretch/Start/Center/End row; it has no between/evenly values, so Grid has no Distribution row
Layout → Arrange → Column order reverse
Layout → Spacing → Gap gap (none / sm / md / lg / xl, 0 / 8 / 16 / 32 / 48px)
Layout → Spacing → Distribution halign (Columns only) — the same field as Horizontal align above, written only as between/evenly from this control

Style

A handoff chip, not a popover: it opens the right-hand panel's Style tab (Background / Spacing / Typography; the optional canvas_builder_motion submodule adds its own Motion tab alongside it). See Styles for what lives there; the toolbar only shapes the band and its columns.

⋯ More

More overflow menu: Section settings, Add section below, Add column, Disable section, Motion, Build with AI (the last two extension-registered)

  • Section settings: opens the popover below.
  • Add column: appends one more column (up to the configured max), identical to the "+ Column" primary action that otherwise sits on the bar itself once there's room for another column.
  • Add section below: inserts a new empty Section immediately after this one.
  • Extension items: other modules can register additional chips or menu rows here (documented contract, Events); canvas_builder_ai adds Build with AI this way.
  • Disable / Enable section: toggles section_disabled. A disabled section never renders on the front end; in the editor it's still visible, overlaid with a hatched indicator.

Section settings

Section settings popover: Element tag buttons (section, div, header, footer, main, article, aside), an ID field, a Classes field, and four "Hide on" viewport icon toggles

  • Element: the semantic HTML tag the Section band renders as.
  • ID / Classes: the section element's id attribute and any extra CSS classes.
  • Hide on: per-viewport visibility, independent per breakpoint (no mobile-first cascade; each toggle stands alone). A hidden banner appears in the editor canvas when the active viewport is one you've hidden.

The panel remembers where you were

The prop-group tab you last used (Style, Motion, Review, whichever) is remembered across reloads, so returning to a page does not drop you back on Content every time.

Collapsed toolbar

Clicking minimize shrinks the bar to a small "Section" pill so it stays out of the way while you work on content beneath it; clicking the pill re-expands the full bar. The preference is remembered for the session (not just this one Section) via sessionStorage.

Collapsed toolbar as a small grip pill labeled "Section" above the selected Section

Hidden children

Some containers hide most of what they hold: a carousel shows one slide, an accordion shows one panel, a tab set shows one pane. In the editor that means children you cannot click, because they are clipped or display:none.

Select the container and a badge appears showing 2 / 5 with previous and next controls. Stepping through reveals each child in turn so you can select and edit it, then restores the container.

A floating badge reading "1 / 2" with prev/next arrows over a Hero Banner carousel

  • It is framework-agnostic. The child count comes from Canvas's own layout model, so it is right no matter how the children render; "which are hidden" is pure geometry and computed style. Nothing knows about any particular carousel library, and closed Bootstrap collapse descendants are detected on the same evidence.
  • A merely scrollable container is left alone. If the children are reachable by scrolling horizontally, revealing one would be a regression, not a help, so the badge does not appear.
  • Revealing does not hide the siblings. Earlier builds isolated the revealed child; it now sits in place among the others, which is far less disorienting in an accordion.
  • The [+] inserter adds after the current item, not at the end, and jumps to what it just added, so building a five-slide carousel is five clicks in the same place rather than a hunt each time.

Where a component declares a slot contract, the badge also offers to add the recommended child for that slot directly.

The Review panel

The Style panel's Review tab (next to Style / Advanced / Create) opens with a read-only, at-a-glance summary of the selected Section, all reflecting the active viewport: a mini layout diagram, the column count cascade across every breakpoint (mobile → large desktop), gap, box model (padding/margin, read from the real rendered element), content width, and background. A brand-new, still-empty Section shows the "Choose a starting layout" prompt here instead (see above).

When a breakpoint's column count doesn't divide evenly (e.g. 3 columns at a count whose wider sibling has more), the Review panel flags an Uneven column wrap warning with a one-click Stretch last column to fill action: it sets fill_last, which stretches the last column to fill the remainder of its row at just the affected breakpoints, computed in pure CSS per viewport.

Backing fields

For developers reading component data directly: every control above writes one of these SDC props, all per-viewport unless noted:

Control Backing field(s)
Width container_type (narrow / contained / full / breakout); not per viewport
Height height (auto / full / min / custom) and height_value (a CSS length, min/custom only); not per viewport
Layout → Structure layout_type, count / count_auto, layout, min_item_width
Layout → Arrange valign / halign (Columns mode) or grid_valign / grid_halign (Grid mode), plus reverse
Layout → Spacing gap (none / sm / md / lg / xl, 0 / 8 / 16 / 32 / 48px)
Section settings tag, section_id, section_classes, and the four hide_at_{viewport} booleans

Admin settings

Everything the toolbar offers is seeded, capped, or made available for editing from Configuration → Content authoring → Canvas Builder (/admin/config/content/canvas-builder, the General tab, a peer of Styles / Components / AI / Blueprints / Usage), behind the Administer Canvas Builder permission. The tab is a vertical-tabs form (GeneralSettingsForm) over the canvas_builder.settings config object, with six sub-tabs:

  • Framework: the active profile radio (Custom / Bootstrap 5 / Tailwind) and the Tailwind Safelist viewer. Covered in Frameworks; it's the same page, just a different tab.
  • Responsive: which viewports the toolbar's device chip (and the Style panel's device picker) offers, plus each one's label, icon, and the CSS class applied when it's hidden (hide_at_*). Widths themselves are read-only here; they come from Canvas / your theme's {theme}.canvas.yml. Disabling a viewport hides it from the editor but keeps any classes already configured for it. The base (narrowest) viewport can't be disabled: every other viewport's mobile-first cascade inherits from it.

Responsive admin tab: a table of Mobile/Tablet/Desktop/XL viewports with Enabled checkboxes, Label and Icon fields, and a Hide class field per row

  • Sections: layout_maps class-mapping tables for the Section band (width, height, alignment): one framework class per value × viewport, live under a classes engine (Bootstrap/Tailwind), inert under the default css_vars engine. See Frameworks → Layout class maps.
  • Columns: the toolbar's actual defaults and caps, plus the Columns family's own layout_maps tables (count, gap, align, column order):

Columns admin tab "Instance defaults": Default layout type radios, a Max columns in editor field set to 6, and a per-viewport table (Mobile/Tablet/Desktop/XL) with Column default, Max allowed, Vertical align, Horizontal align, and Gap dropdowns, the last three columns visually grouped by a left border into Structure/Arrange/Spacing bands

- **Default layout type**: Columns or Grid, applied to every newly
  placed Section.
- **Max columns in editor** (`layout_defaults.columns.max_count`): the
  hard ceiling (1–6) for the toolbar's Structure-tab column-count row and
  the "+ Column" action; every per-viewport **Max allowed** below is
  bounded by it.
- The **per-viewport table** lists **Column default** (the count a new
  Section starts with at that breakpoint), **Max allowed** (`vp_max`, a
  per-viewport ceiling beneath the global max), **Vertical align**,
  **Horizontal align**, and **Gap**: the seed values for `valign`,
  `halign`, and `gap` a freshly placed Section carries before an author
  touches the Arrange/Spacing tabs. Every column past the base viewport
  defaults to **— (inherit)**, matching the mobile-first cascade the
  toolbar itself reads at render/edit time.
  • Grid: a pointer note (Grid shares the Columns tab's instance defaults) plus a free-text Grid minimum-item-width list and the Grid family's own layout_maps tables (grid alignment). The toolbar's own Min column width pills (100–400px) come from the Section SDC's fixed prop enum, not from this list.
  • Section templates: one table, one row per layout preset (the 12 built-ins, in order, then any custom ones), each with an Enabled checkbox controlling whether it appears in the toolbar's "Choose a column layout" chooser and "More layouts" gallery. Built-in rows are always present and tunable (label locked; Type/Mobile/Tablet/Desktop/Large/Layout ratio editable) but not removable, only turned off. Custom rows add every field including the label, plus a Remove button. A row whose column count exceeds the Columns tab's Max columns in editor value is force-disabled, with the reason shown inline next to its checkbox.

Section templates admin tab: one table listing the 12 built-in layout rows (label locked, Enabled checkbox, editable Type/Mobile/Tablet/Desktop/Large/Layout ratio) followed by custom rows with an editable label and Remove button, and an Add template button

How this plays with your framework

All Section/Column layout (count, gap, alignment, height) renders through the layout engine set by your active framework profile, completely independent from the toolbar UI itself. Under the default Custom profile it's plain CSS custom properties and CSS Grid; under Bootstrap 5 or Tailwind, the same values additionally emit mapped utility classes alongside that CSS-grid layout. Switching frameworks changes which classes ride along, never the layout mechanics. See Frameworks → Layout class maps for the full per-family mapping table, and the Tailwind safelist if you're on a purging Tailwind build: the toolbar's runtime-derived classes need to be told to your build the same way the Style panel's per-side spacing classes do.