Skip to main content

Single Directory Components (SDC) in Drupal 11

Aug 20, 2026

Build Drupal UI components that keep Twig, metadata, CSS and JavaScript together.

SDC

This guide was reviewed and updated for Drupal 11.4 in August 2026. It uses the current Single-Directory Components API in Drupal core, including component metadata, typed props, slots, variants, Twig rendering and the PHP component render element.

Imagine opening one component directory and finding everything needed to understand, render and maintain that piece of UI. That is the promise of Single-Directory Components (SDC): Drupal’s component model for keeping the template, metadata, styles and JavaScript together instead of scattering them across a theme or module.

What are Single-Directory Components (SDC)?

Single Directory Components (SDC) are Drupal core’s approach to implementing components. In SDC, all the files needed to render a component are organized into a single directory, which is why it's named that way. This directory includes Twig, YAML, and optionally CSS, JavaScript, and other files. When the template is used, SDC will automatically generate a library to load the CSS and JavaScript.

Key points

Here are the general key points of Single Directory Components (SDC) in Drupal:

  1. Unified Structure: All related files for a component (CSS, JavaScript, templates, configuration) are grouped in a single directory.
  2. Improved Maintainability: Simplifies updates and debugging by keeping all component files together.
  3. Consistency: Promotes a standardized and organized structure for components across the project.
  4. Enhanced Reusability: Makes it easier to reuse components across different projects or parts of a project.
  5. Better Organization: A well-organized directory structure helps developers quickly find and work with the files they need, boosting productivity and reducing errors.

These points highlight the advantages and the structured approach that SDC brings to Drupal development.

How to Use Single Directory Components in Drupal 11

SDC is part of Drupal 11 core. There is no separate module to download or enable. Components placed inside a components directory in a custom theme or module are discovered by Drupal and can be rendered from Twig or PHP.

A practical Drupal 11 workflow is:

  1. Create the component directory and its *.component.yml and *.twig files.
  2. Declare props, slots and optional variants in the metadata file.
  3. Clear Drupal caches after adding a component or changing its metadata.
  4. Render the component with its provider and machine name, for example my_theme:button.

For local development, disable CSS and JavaScript aggregation under Configuration → Development → Performance. Twig debug and Twig cache controls are available under Configuration → Development → Development settings.

These options make component boundaries and template changes easier to inspect, but they should remain disabled on production.

How to create a new component

The following button is a complete Drupal 11 SDC example. It has two required props, one optional slot and two variants.

my_theme/
└── components/
    └── button/
        ├── button.component.yml
        ├── button.twig
        ├── button.css
        └── button.js

button.component.yml

$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: Button
status: stable

props:
  type: object
  required:
    - label
    - url
  properties:
    label:
      type: string
      title: Label
    url:
      type: string
      title: URL
    attributes:
      type: Drupal\Core\Template\Attribute
      title: Attributes

slots:
  icon:
    title: Icon

variants:
  primary:
    title: Primary
  secondary:
    title: Secondary

Props are predictable values validated against the schema. Slots contain markup or renderable content and are represented by Twig blocks.

button.twig

<a{{ attributes.addClass([
  'button',
  'button--' ~ (variant|default('primary'))
]) }} href="{{ url }}">
  {% block icon %}{% endblock %}
  <span>{{ label }}</span>
</a>

If button.css and button.js use the same machine name as the component, Drupal creates and attaches the component library automatically. Declare additional dependencies through libraryOverrides in the metadata file when required.

How to render an SDC component

The component ID combines the provider machine name and component machine name: my_theme:button.

Render props with Twig include()

Use include() when the component only needs props and its slots can stay empty.

{{ include('my_theme:button', {
  label: 'Read more',
  url: path('entity.node.canonical', {node: node.id}),
  variant: 'primary'
}, with_context = false) }}

Populate a slot with Twig embed

Use embed when you need to fill a declared slot. The block name must match the slot name in button.component.yml.

{% embed 'my_theme:button' with {
  label: 'Read more',
  url: path('entity.node.canonical', {node: node.id}),
  variant: 'primary'
} only %}
  {% block icon %}
    {{ content.field_icon }}
  {% endblock %}
{% endembed %}

Render the component from PHP

Drupal 11 also provides a component render element. Use the singular #variant property; #props contains schema-defined values, while #slots accepts render arrays or scalar values.

use Drupal\Core\Url;

/** @var \Drupal\node\NodeInterface $node */
$build['button'] = [
  '#type' => 'component',
  '#component' => 'my_theme:button',
  '#variant' => 'primary',
  '#props' => [
    'label' => $this->t('Read more'),
    'url' => Url::fromRoute('entity.node.canonical', [
      'node' => $node->id(),
    ])->toString(),
  ],
  '#slots' => [
    'icon' => [
      '#markup' => '&rarr;',
    ],
  ],
  '#attributes' => [
    'data-track' => 'read-more',
  ],
];

With Twig debug enabled, Drupal adds component boundary comments containing the component ID—and the selected variant when one is used—so you can confirm which component produced the markup.

Conclusions

SDC becomes most valuable when a component has to be understood or changed months after it was created. Its metadata documents the contract, its Twig file owns the markup, and its CSS and JavaScript stay next to the UI they support.

The real improvement is not simply a tidier folder. It is a more predictable development workflow: components are easier to find, review, reuse and test without hunting through unrelated theme files. With SDC stable in Drupal 10.3+ and built directly into Drupal 11, it is now a practical foundation for component-based Drupal theming rather than an experiment to watch from a distance.

Snoopy
Enjoying the article?

Consider subscribing to our social media.

We much appreciate it.