Media Image

Filed Under

The same session showed up at two different Drupal camps this year — Florida DrupalCamp and DrupalCamp New Jersey — with the same title: "Creating single directory components with Drupal Canvas in mind."48 When I looked at how those recordings performed against everything else those channels published, they weren't close. One did 5.3x its channel's median. The other did 4.6x.

Two camps. Two audiences. Same spike.

That tells me something specific: site builders have figured out that Canvas is coming, and they've figured out that the thing standing between them and Canvas is a skill they don't have yet. Not "how do I install a page builder." How do I build a component that Canvas can actually use.

So let's build one. Start to finish, from an empty folder to a component sitting in the Canvas component list, with the parts that trip people up called out as we hit them.

Why we're talking about components and not on a page builder

If your team is still maintaining a stack of Paragraph types, Layout Builder overrides, custom display modes, and a separate frontend layer, you already know what that costs. Echo Flow calls it the Paragraph tax — expensive to model, expensive to maintain, expensive to migrate, and expensive to train editors on.5 Every time requirements shift, somebody pays it in hours, spread across enough tickets that nobody adds up the number.

Canvas isn't another layout tool stacked on top of Layout Builder. It's positioned as Drupal's official visual page builder, and it's built on Single Directory Components.5 Vardot makes the same point from the architecture side: SDC underpins Canvas, and a well-built component library stops being a theming convenience and starts being infrastructure.7

Which means the leverage isn't in learning the Canvas UI. The UI is the easy part. The leverage is in the components you hand it.

What an SDC actually is

An SDC is a folder. That's the whole idea, and it's why Lullabot pitched it for core in the first place — template files, stylesheets, scripts, and assets were scattered across big codebases, and front-end developers had to learn a pile of Drupal internals just to get CSS onto a page.3

Components live in a components/ directory inside your theme or module, and can be nested in subdirectories like components/atoms/ if you want the organization.1 Every component requires exactly two files:1

  • my-component.component.yml — the definition: metadata, schema, configuration
  • my-component.twig — the template (note the extension: .twig, not .html.twig)

Everything else is optional. my-component.css and my-component.js load automatically when they're named after the component, and README.md, thumbnail.png, and asset directories are all supported.1 No library definition. No attach. Name the file correctly and it loads.

SDC has been in core since Drupal 10.3. On 10.2 and earlier you had to enable the module yourself.1

Build it: a callout component

We'll build a callout — a boxed note with a style variant and a slot for whatever content goes inside. Small enough to type in five minutes, real enough that you'll actually use it.

Make the folder: (change MY-THEME to the name of your theme)

themes/custom/MY-THEME/components/callout/ 

Step 1 — define it. In callout.component.yml:

name: Callout
group: MY-THEME
props:
  type: object
  required:
    - tone
  properties:
    tone:
      type: string
      title: Tone
      description: "Visual treatment: 'info', 'warning' or 'success'."
      enum: ['info', 'warning', 'success']
      examples: ['info']
    heading:
      type: string
      title: Heading
      description: Optional bold line above the content.
      examples: ['Before you upgrade']
slots:
  content:
    title: Content
    description: The body of the callout.

The shape here follows the official quickstart, which uses the same props / properties / slots structure with enum to constrain a string.2 Props are the values you pass in. Slots are the markup you nest inside.

Step 2 — the markup. In callout.twig:

{%
  set classes = [
    'callout',
    'callout--' ~ tone|clean_class,
  ]
%}
<div{{ attributes.addClass(classes) }}>
  {% if heading %}
    <p class="callout__heading">{{ heading }}</p>
  {% endif %}
  <div class="callout__content">{{ content }}</div>
</div>

Same pattern the docs use for their chip example: build a class array, run the variant through clean_class, and let attributes.addClass() merge in anything Drupal is passing down.2

Step 3 — style it. callout.css, with rules for .callout, .callout--info, .callout--warning, and .callout--success. It loads on its own because of the filename.1

Step 4 — use it from a template. (not required if you're only using it in Canvas) From node.html.twig or anywhere else:2

{% set callout_body %}
  <p>Back up your database before running updates.</p>
{% endset %}

{{ include('MY-THEME:callout', {
  tone: 'warning',
  heading: 'Before you upgrade',
  content: callout_body,
}, with_context = false) }}

The namespaced syntax — 'MY-THEME:callout' — is how you address a component. Props and slot values go in as an object.2

Note the with_context = false. Keep reading, because that one is not a style preference.

The parts Canvas actually reads

This is where a component that works in Twig quietly fails to show up properly in Canvas. Mike Anello's camp session — the one that outlier-ed twice — is mostly about this gap, and it's worth going through his list carefully.4

  1. No *.component.yml, no props. Without the definition file, Canvas has no idea what props or slots your component has.4 Schemas are optional for themes and "highly recommended" in the official docs, and mandatory for modules.1 For Canvas work, treat "optional" as theoretical.
  2. Don't rely on context. Your component needs to work with with_context: false or only, and the props and slots defined in the YAML need to be a one-to-one match with the variables in your Twig.4 Canvas is passing values in directly. Anything your template picked up ambiently from the render context won't be there.
  3. name is the identifier Canvas shows. description isn't used.4
  4. status controls visibility. By default Canvas shows components marked stable, experimental, or deprecated. A component with a status of obsolete won't be available. No status key at all means the component is available.4
  5. group organizes the component list. Set group: MY-THEME and your components cluster together; leave it out and everything lands in "Other."4
  6. examples earn their keep. Anello's slides note that type, title, enum, examples, description, and required all feed the Canvas prop form, and that examples act as default values and inform the component preview.4 That's why the callout above has them. Skip them and your editors get an empty form and a blank preview.

He also points at the SDC Devel module and drush sdcv for validating components, plus enforce_prop_schemas: true in your theme's info file to make schema compliance non-optional.4 The official docs cover the validation side too: it needs the justinrainbow/json-schema package (comes with drupal/core-dev) and assertions turned on, which may mean adding ini_set('zend.assertions', 1); to settings.php.1

Dropping it into Canvas

Install is what you'd expect:6

composer require drupal/canvas
drush en canvas -y
drush cr

One troubleshooting note, offered with a caveat. Bonnici's Canvas walkthrough reports that components won't appear until you add $settings['extension_discovery_scan_tests'] = TRUE; to settings.php or settings.local.php.6 I can't find that requirement in the official SDC documentation, and the setting's usual job is scanning test directories — so treat it as a fix to try if your components don't show up, not a step to run blindly on production.

Versions move fast here, so anchor yourself to dates rather than to "current." Anello's February camp demo ran Drupal CMS 2.0 with core 11.3.3 and Canvas 1.1.0.4 Echo Flow reported Canvas 1.3.2 on Drupal 11.3.5, shipping in Drupal CMS 2.1, as of the end of March 2026.5 Check what's current before you plan a build around a specific release.

Try it with Jarvis

If you don't have a test site set up with Canvas yet, give Jarvis a try.  It's our Drupal 11 theme with Canvas already working and 21 components you can look at and learn from.  

Learn more about the Jarvis theme

 

What doesn't work yet

This is the part most tutorials leave out, and it's the part that saves you a weekend.

  • Variants aren't supported in Canvas yet. Component variants landed in Drupal core 11.2.0, but Anello's slides list them as not (yet) supported on the Canvas side.4 Which is exactly why the callout above uses an enum prop for its tone instead of a variant.
  • Prop types are uneven. string, number, integer, and boolean work as expected. Array support is incomplete, and object isn't supported without Canvas $ref schemas.4 Design your props around the four that work.
  • Rich text is doable. String props can be configured to expose a CKEditor field in Canvas.4
  • Changing group may need a reinstall. Anello flags — with a question mark of his own — that seeing group changes may require uninstalling and reinstalling the module or Canvas.4

None of this is a reason to wait. It's a reason to build simple components with flat, well-typed props, which is what you should be doing anyway.

Where to start this week

Don't rebuild your Paragraph library. Pick one thing and take it end to end:

  1. Find the most-repeated visual pattern on your site. A callout, a card, a stat block.
  2. Build it as an SDC in your theme, with a full *.component.ymlname, group, typed props, enum where the value is constrained, and examples on every prop.
  3. Make it work with with_context = false. If it breaks, you found a hidden dependency, and better now than in Canvas.
  4. Install Canvas on a local copy and confirm the component shows up in the right group with a usable prop form.

One component. One afternoon. After that, the next one takes twenty minutes, and you'll have a real answer to what your component library should look like before the decision gets made for you by a deadline.

Two camps put the same session on stage and both times the room showed up. That's the signal. The work is a folder with two files in it.

Download the SDC


 

References

  1. Creating a single-directory component — Drupal.org documentation
  2. Quickstart | Using Single-Directory Components — Drupal.org documentation
  3. Single Directory Components in Drupal Core — Mateu Aguiló Bosch, Lullabot
  4. Creating Single Directory Components with Drupal Canvas in mind — Michael Anello (DrupalEasy), Florida DrupalCamp session slides
  5. Stop Patching Drupal: Switch to Canvas and Reset Your Whole Workflow — Echo Flow
  6. Building with Drupal 11 Canvas: Creating a Custom Hero Component — Bonnici
  7. Component-based design in Drupal: SDC, Canvas & AI — Ala Batayneh, Vardot
  8. Creating single directory components with Drupal Canvas in mind — DrupalCamp New Jersey session

 


 

 

Article Summary (Drupal AI Generated)

Learn how to future-proof your Drupal site by building Single Directory Components (SDCs) for the new Canvas visual page builder. SDCs streamline frontend development by grouping templates, styles, and scripts in a single folder and are essential for leveraging Canvas, as highlighted in popular sessions at Florida DrupalCamp and DrupalCamp NJ. This guide walks you through creating a reusable callout component from scratch, explains Canvas’s unique requirements, and covers best practices for component schema, prop definitions, and troubleshooting. Start preparing your component library today for a faster, more flexible Drupal editing experience!