SDC Component Reuse
When to Use
When you need reusable UI components (buttons, cards, modals, forms) used across multiple pages, content types, or blocks. SDCs (Single Directory Components) are Drupal's native component system (core since 10.3).
Props and Slots
| Mechanism | Type | Use When |
|---|---|---|
| Props | Strictly-typed data (strings, booleans, numbers, arrays) | Pass configuration values, labels, settings |
| Slots | Renderable content (HTML, nested components) | Pass flexible content, nested markup |
Decision
| If you need... | Use... | Why |
|---|---|---|
| Reusable button with variants | SDC with props for variant/size | Single component, customized via props |
| Card with variable content | SDC with slots for header/body/footer | Flexible content injection |
| Component with nested components | Slots | Compose components from other components |
| Component used once | Standard Twig template | Don't create SDC until reused 2+ times |
| Design system consistency | SDCs for all UI patterns | Centralized, reusable, maintainable |
Pattern
# mytheme/components/card/card.component.yml
$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/modules/sdc/src/component.schema.json
name: Card
status: stable
props:
type: object
properties:
variant:
type: string
enum: [default, highlighted, compact]
default: default
title:
type: string
title: Card Title
slots:
header:
title: Card Header
body:
title: Card Body
footer:
title: Card Footer
{# mytheme/components/card/card.twig #}
<div class="card card--{{ variant }}">
{% if slots.header %}
<div class="card__header">
{{ slots.header }}
</div>
{% endif %}
{% if title %}
<h3 class="card__title">{{ title }}</h3>
{% endif %}
<div class="card__body">
{{ slots.body }}
</div>
{% if slots.footer %}
<div class="card__footer">
{{ slots.footer }}
</div>
{% endif %}
</div>
{# Using the component #}
{% include 'mytheme:card' with {
variant: 'highlighted',
title: 'Welcome',
slots: {
body: content.field_body,
footer: content.field_links,
}
} %}
Reference: core/modules/sdc/, Radix theme components at themes/contrib/radix/components/
Component Composition
{# Nesting components via slots #}
{% include 'mytheme:modal' with {
slots: {
content: include('mytheme:card' with {
title: 'Modal Card',
slots: {
body: 'Card inside modal',
}
})
}
} %}
Common Mistakes
- Creating component for single use — Wait until component is reused 2+ times (Rule of Three)
- Duplicating components instead of using props — Use props/slots to make one flexible component instead of creating multiple similar components
- Props for renderable content — Use slots for HTML/components, props for simple data
- Missing component schema — Always define
component.ymlfor validation and IDE autocomplete - Not using design tokens — Define colors, spacing, typography in CSS custom properties, reference in component styles