Skip to content

Canvas · Layout Builder · Paragraphs · Twig

Architecture

Four different Drupal placement methods reach the same components without changing how those components are built or themed. This page is the mental model: how the pieces fit, how a component actually reaches the page, and what each path requires.

How a component reaches the page

One decision tree, four real paths.

flowchart TD
    Start{"How does this<br/>component reach the page?"}
    Start -- "hand-coded in a theme template" --> Direct["Theme developer writes<br/>{% include 'ixm_blocks:&lt;component&gt;' %}<br/>directly, props written by hand"]
    Start -- "editor places it: Canvas" --> CanvasPath["Canvas page places the SDC directly<br/>fields = props, 1:1"]
    Start -- "editor places it: Layout Builder" --> LB["Enable the ixm_blocks_&lt;type&gt; submodule,<br/>then Layout Builder places an IXM block;<br/>its block--ixm-blocks-*.twig<br/>bridges paragraph fields to props"]
    Start -- "editor places it: Paragraphs field only<br/>(no Layout Builder)" --> ParaNote["Needs a hand-written<br/>paragraph--*.twig include,<br/>not shipped today, same<br/>mechanism as hand-coded"]

    Direct --> Render["Same SDC renders: identical markup either way"]
    CanvasPath --> Render
    LB --> Render
    ParaNote --> Render

The bridge, per path

All four paths render the same SDC, so the markup is identical regardless of which one built it. What differs is who writes the bridge:

Path Who builds the bridge Mechanism
Canvas Canvas itself Maps fields to props automatically, 1:1
Layout Builder The ixm_blocks_<type> submodule block--ixm-blocks-*.twig reads the paragraph's fields and passes them in as props
Hand-coded in a theme You {% include 'ixm_blocks:<component>' %} written directly in a theme template
Paragraphs field only You A paragraph--*.twig bridge — not shipped today

The connector submodule is just a translator: no styling or markup of its own, only the paragraph-to-props mapping. See Upgrading for what moved when it replaced the old inline-markup block templates.

Styling is a separate question — see the component-set split and Theming.

Companion modules per path

What to install alongside ixm_blocks for a fully functional site, by path. Each row is additive only for that path.

Canvas Layout Builder Paragraphs field only Direct SDC include
Hard requirements (already enforced) canvas, bootstrap_components paragraphs, entity_reference_revisions, block_content, bootstrap_components, twig_tweak (ixm_blocks' own dependencies) + the relevant ixm_blocks_<type> submodule enabled paragraphs, entity_reference_revisions, bootstrap_components bootstrap_components
Recommended companions bootstrap_ui_kit: icon pack backing icon_name props; canvas_icon_picker: icon-picker widget for that prop; canvas_builder: layout and styles control for Canvas (SWAT already ships its own layout SDCs, which may cover your layout needs without this) block_library: tray icons in the offcanvas placement UI; bootstrap_layout_builder: Bootstrap layout sections for Layout Builder; bootstrap_styles: Bootstrap style options on sections and blocks; section_library: reusable, exportable layout sections; layout_builder_blocks: extra block types for Layout Builder None: requires writing your own paragraph--*.twig bridge; no shipped module covers this today None: just the theme itself

Not tied to any single path: a theme overriding an IXM Blocks or Bootstrap Components template via core's replaces: key should also install sdc_prop_inherit, so the override's prop schema tracks the original automatically instead of drifting out of sync by hand. See Frameworks.

The two-layer contract

Each component exposes two levels of control, and knowing which one to reach for is most of what there is to learn.

--theme-*

The shared vocabulary. One accent, one type ramp, one spacing scale, read by every component. Set these once in a theme and the whole set moves together.

--theme-color-primary: #10564f;

--<component>-*

Per-component knobs. Reach for these only when one component needs to diverge from the shared decision.

--statistic-item-divider-width: 0;
--ixm-tabs-indicator-color: #10564f;
--ping-pong-measure: 40ch;

Component tokens fall back to theme tokens, which fall back to Bootstrap's own defaults. So a theme that sets nothing still renders correctly, it just renders as Bootstrap.

/* statistic.css: the component never names a colour */
.statistic-item {
  --statistic-item-divider-color: var(--theme-color-border, var(--bs-border-color, #dee2e6));
}