Using your new single-directory component

Last updated on
6 February 2026

This documentation needs work. See "Help improve this page" in the sidebar.

Figure out the component ID

To use a component you'll need to know the component ID. This is the machine name of the module or theme that provides the component, plus the name of the component itself, separated by a colon. Examples:

  • {module}:{component}. Example: sdc_example:button where sdc_example is the module name, and button is the component name.
  • {theme}:{component}. Example: olivero:chip where olivero is the theme name, and chip is the component name

Once you know the component ID there are two ways you can make use of it.

Using your component through a render array

SDC comes with its own render element in order to be usable from PHP code. This is the preferred way if you want to keep your theme shareable and agnostic and make Drupal aware of your component usage.

Model:

Render property PHP type Description
#component String Mandatory. Full component ID: {provider}:{component_id}
#variants (since Drupal 11.2+, not supported before) String Optional. Name of the variant to use.
#slots Array Optional. Associative array, keyed by slot ID. Each value is a Drupal renderable.
#props Array Optional. Associative array, keyed by prop ID. Each value must be valid according to the prop JSON schema.
#attributes Attribute Drupal 11.3+ Only: Optional. Attribute object, or if associative array, will be converted to an Attribute object.

Notes:

  • "Universal" #cache and #attached render properties are available.

Most of the time, you will use this render element as the return value of configurable plugins related to display building:

Example:

<?php
return [
  '#type' => 'component',
  '#component' => 'sdc_examples:my-cta',
  '#props' => [
    'label' => t('Click Me'),
  ],
  '#slots' => [
    'body' => [
      '#type' => 'html_tag',
      '#tag' => 'span',
      '#value' => t('I am a render array in a slot.'),
    ]
  ],
];

Using your component in Twig template

Twig functions

When using a render element is not possible, you can use your component in an *.html.twig template use Twig’s built in include or embed functions, according to the way you are printing slots in your template:

Slot in the component template When called from another template
{{ label }} {{ include('provider:my_component', {label: label}, with_context = false) }}
{% block label %}{% endblock %} {% embed 'provider:my_component' only %}
{% block label %}{{ label }}{% endblock %}
{% endembed %}
{% block label %}{{ label }}{% endblock %} Compatible with both include and embed
Use include():

Use the Twig include() function if there is no data being sent to slots or if you are printing your slots as Twig variables in the component template.

Example of how to include the sdc_examples:my-button component from a Drupal Twig template:

{{ include('sdc_examples:my-button', { text: 'Click Me', iconType: 'external' }, with_context = false) }}

You’ll need to provide the component ID ([module/theme name]:[component]) of the component.

with_context = false parameter is optional but recommended to avoid unexpected side-effects.

Read more about include() in the Twig documentation.

Use {% embed %}:

Use a Twig {% embed %} tag only if you are using Twig blocks to manage your slots in the component template.

Example of how to pass in a slot (Twig block) in a card component:

{% embed 'sdc_examples:my-card' with { header: label } only %} 
  {% block card_body %}
    {{ content.field_media_image }} 
    {{ content|without('field_media_image') }} 
    {{ include('sdc_examples:my-button', { text: 'Like', iconType: 'like' }, with_context = false) }} 
  {% endblock %} 
{% endembed %}

only  keyword is optional but recommended to avoid unexpected side-effects.

Read more about embed in the Twig documentation.

About {% include %} tag

This tag is not recommended according to Twig documentation:

It is recommended to use the include function instead as it provides the same features with a bit more flexibility:

  • The include function is semantically more "correct" (including a template outputs its rendered contents in the current scope; a tag should not display anything)
  • The include function is more "composable"
  • The include function does not impose any specific order for arguments thanks to named arguments.

Source: https://twig.symfony.com/doc/3.x/tags/include.html

Slots & props data in a Drupal template

Some templates are providing distinct variables for data expected in slots and props:

In node.html.twig:

  • content variable has the data to send to slots
  • node variable has the data to send to props

In user.html.twig:

  • content variable has the data to send to slots
  • user variable has the data to send to props

And so on.

Example with icons from the Core's Icon API, which can be send to both slots and props.

In component definition In the presenter template In the component template
slots:
icon:
title: Icon
{{ include('my_theme:button', {
label: node.title,
icon: content.field_icon
}, with_context = false) }}
{{ icon }}
props:
type: object
properties:
icon:
title: Icon
type: object
properties:
pack_id:
type: string
icon_id:
type: string
settings:
type: object
required:
- pack_id
- icon_id
{{ include('my_theme:button', {
label: node.title,
icon: node.field_icon
}, with_context = false) }}
{{ icon(icon.pack_id, icon.icon_id, icon.settings) }}

Manual enablement needed in 10.2.x or earlier

Starting with Drupal 10.3, Single-Directory Components became part of Drupal Core's render system. If you're using Drupal 10.2 or earlier, you must enable the module in Core manually to use this feature.

Help improve this page

Page status: Needs work

You can: