Props to Twig Variables
When to Use
Use this when mapping React component props to SDC
component.ymlproperties and Twig template variables. This is the core translation step for every component.
Decision: Prop Type Mapping
| React Prop Type | component.yml Type | Twig Usage | Notes |
|---|---|---|---|
string |
type: string |
{{ title }} |
Direct output |
boolean |
type: boolean |
{% if active %} |
Conditional logic |
number |
type: integer or type: number |
{{ count }}, {% if count > 0 %} |
Use integer for whole numbers |
'sm' \| 'md' \| 'lg' (union) |
type: string + enum |
{% if size == 'lg' %} |
Add meta:enum for UI labels |
string \| undefined (optional) |
Omit from required |
{{ value\|default('fallback') }} |
Optional props use default filter |
ReactNode (children) |
Use slots: not props |
{% block content %}{% endblock %} |
Renderable content always goes in slots |
() => void (callback) |
No equivalent | N/A | Event callbacks become JS behaviors |
Record<string, string> (object) |
type: object |
{% for key, val in obj %} |
Avoid complex objects; prefer flat props |
string[] (array) |
type: array + items |
{% for item in items %} |
Prefer slots for repeated complex content |
React.HTMLAttributes |
attributes variable |
{{ attributes }} |
Drupal's Attribute object handles all HTML attributes |
Pattern: String Prop with Default
React
interface AlertProps {
message: string;
heading?: string;
}
function Alert({ message, heading = 'Notice' }: AlertProps) {
return (
<div className="alert">
<h3>{heading}</h3>
<p>{message}</p>
</div>
);
}
component.yml
props:
type: object
required:
- message
properties:
heading:
title: Heading
type: string
slots:
message:
title: Message
Twig
{% set heading = heading|default('Notice') %}
<div {{ attributes.addClass('alert') }}>
<h3>{{ heading }}</h3>
<div>{{ message }}</div>
</div>
Pattern: Enum Prop (Variant)
React
type Variant = 'primary' | 'secondary' | 'accent' | 'error';
function Badge({ variant = 'primary', children }) {
return <span className={`badge badge-${variant}`}>{children}</span>;
}
component.yml
variants:
default: { title: Default }
primary: { title: Primary }
secondary: { title: Secondary }
accent: { title: Accent }
error: { title: Error }
slots:
label:
title: Label
Twig
{% set classes = [
'badge',
variant and variant != 'default' ? 'badge-' ~ variant,
] %}
<div {{ attributes.addClass(classes) }}>{{ label }}</div>
Common Mistakes
- Wrong: Creating a
classesprop of typestring→ Right: Drupal'sattributesvariable already handles this - Wrong: Making renderable content (HTML) a
stringprop → Right: String props get escaped; slots preserve render arrays and cache metadata - Wrong: Omitting
meta:enumon enum props → Right: Without labels, site builders see raw values (sm,md,lg) instead of human-readable names