From drupal-core
Create and maintain Drupal Single Directory Components (SDC) -- directory structure, component.yml schema, Twig templates, props/slots, compound patterns, and review criteria.
npx claudepluginhub ajv009/drupal-devkitThis skill uses the workspace's default tool permissions.
You are an expert at creating Single Directory Components for Drupal 10.3+ themes. SDC is Drupal core's standard for self-contained, reusable UI components.
Generates Webflow Code Component boilerplate with React component, .webflow.tsx definition file, and optional styling. Checks prerequisites and sets up missing webflow.json/config/dependencies.
Craft CMS 5 front-end Twig development — atomic design, template architecture, component patterns, Vite buildchain. Covers the full site template surface: atoms, molecules, organisms, props/extends/block pattern, layout chains, view routing, content builders, image presets, Tailwind named-key collections, multi-brand CSS tokens, JavaScript boundaries (Alpine/DataStar/Vue, tabs, accordions, interactive components), Vite asset loading, and front-end auth (login, registration, password reset, user profiles). Triggers on: {% include ... only %}, {% embed %}, _atoms/, _molecules/, _organisms/, _views/, _builders/, _boilerplate/, component--variant.twig, _component--props.twig, image presets, Tailwind class collections, collect({}), utilities prop, multi-brand theming, data-brand, hero sections, card components, content builders, Matrix block rendering, craft.vite.script, vite.php, vite.config.ts, nystudio107, buildchain, asset loading, per-page scripts, Blitz, static caching, page caching, dynamic caching with Sprig, ImageOptimize, Imager-X, responsive images, srcset, image transforms, SEOmatic, meta tags, OpenGraph, JSON-LD, Sprig, htmx, multi-language site, language switcher, hreflang, localization, Formie, form styling, login form, registration form, user authentication front-end, RSS feed, Atom feed, JSON Feed, XML sitemap, feed.xml, sitemap.xml, |rss, |atom, search page, search results, .search(), search index, search form, search configuration, headless, headless CMS, GraphQL queries, preview tokens, Next.js, Nuxt, Astro, consuming GraphQL API, front-end framework integration. Always use when creating, editing, or reviewing any Craft CMS front-end Twig template, component, layout, view, builder, buildchain configuration, or front-end auth flow — including plugin template integration (Blitz, SEOmatic, Sprig, Formie, Imager-X). Do NOT trigger for PHP plugin/module development or content modeling decisions.
Builds accessible, responsive, performant frontend components using design systems, modern CSS, WCAG patterns, and React/Vue/Svelte examples.
Share bugs, ideas, or general feedback.
You are an expert at creating Single Directory Components for Drupal 10.3+ themes. SDC is Drupal core's standard for self-contained, reusable UI components.
Each component lives in its own directory under the theme's components/ folder, organized by atomic design categories:
01-atoms/ -- Basic building blocks (buttons, badges, icons)02-molecules/ -- Combinations of atoms (cards, form fields, media objects)03-organisms/ -- Complex sections (headers, footers, hero banners, card grids)Each component directory contains:
{name}.component.yml -- Metadata and props schema (REQUIRED){name}.twig -- The Twig template (REQUIRED){name}.css -- Component-scoped styles (optional but recommended){name}.js -- JavaScript behaviors (only if interactive)The .component.yml file defines the component's interface:
$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: Human Readable Name
status: stable
subtype: card
group: Molecules/Marketing
description: 'A short description of what this component does and when to use it.'
long_description: |
A longer description with more detail.
visual_description: |
What the component looks like visually.
typical_usage: |
Where and how this component is typically used.
props:
type: object
properties:
title:
type: string
title: Title
examples: ["Example Title"]
description:
type: string
title: Description
examples: ["Example description text"]
variant:
type: string
title: Variant
enum: ["primary", "secondary", "outline"]
default: "primary"
full_width:
type: boolean
title: Full Width
default: false
SDC supports standard JSON Schema prop types:
Simple types:
type: string -- text values, also use for links/URLstype: boolean -- true/false togglestype: integer -- whole numberstype: number -- decimal numbersObject types (structured data):
image:
type: object
title: Image
properties:
src:
type: string
title: Image source URL
alt:
type: string
title: Alt text
width:
type: integer
title: Width
height:
type: integer
title: Height
examples:
- src: 'https://placehold.co/1920x1080'
alt: 'Placeholder image'
width: 1920
height: 1080
Array types (lists):
tags:
type: array
title: Tags
items:
type: string
examples:
- ["Drupal", "Frontend", "SDC"]
Complex structured props (buttons, links, CTAs):
For buttons, links, and similar structured items, you can model them as objects or flatten them into separate string props depending on the use case:
# Option A: Object prop (clean, grouped)
primary_button:
type: object
title: Primary Button
properties:
label:
type: string
title: Label
url:
type: string
title: URL
examples:
- label: "Get Started"
url: "https://example.com"
# Option B: Flat string props (simpler, more explicit)
primary_button_label:
type: string
title: Primary Button Label
examples: ["Get Started"]
primary_button_url:
type: string
title: Primary Button URL
examples: ["https://example.com"]
ALWAYS use props for all component content. Every piece of data the component displays -- titles, descriptions, buttons, links, images -- should be a prop. Props give the site builder direct, field-level control over each value.
Example -- Hero component with props:
props:
type: object
properties:
media:
type: object
title: Background image
properties:
src:
type: string
alt:
type: string
width:
type: integer
height:
type: integer
examples:
- src: 'https://placehold.co/1920x1080'
alt: 'Hero background'
width: 1920
height: 1080
heading:
type: string
title: Heading
examples: ["Welcome to Our Site"]
subheading:
type: string
title: Subheading
examples: ["Discover what we have to offer"]
primary_button_label:
type: string
title: Primary Button Label
examples: ["Get Started"]
primary_button_url:
type: string
title: Primary Button URL
examples: ["https://example.com"]
height:
type: string
title: Height
enum: ['full', 'large', 'ribbon']
default: 'full'
Slots are for composing other components inside your component. Do NOT use slots by default. Only use slots when:
When in doubt, use props. A hero with heading + description + button should use props, NOT a slot.
YAML syntax for slots:
slots:
items:
title: "Content items"
Twig syntax -- use {% block %} for each slot:
<div class="grid">
{% block items %}{% endblock %}
</div>
{% block slot_name %}{% endblock %}{{ media.src }}, {{ media.alt }}, {{ media.width }}, {{ media.height }}<img> tags or Drupal's responsive image patterns:
{% if media.src %}
<img src="{{ media.src }}" alt="{{ media.alt|default('') }}"
width="{{ media.width }}" height="{{ media.height }}"
loading="lazy">
{% endif %}
{% if prop_name %} for optional props{{ prop_name|default('fallback') }} for safe defaultsTwo main approaches, depending on the theme's setup:
Tailwind CSS (if the theme uses it):
Use utility classes directly in Twig templates. No separate CSS file needed for most components.
<section class="py-16 px-4 bg-gray-50">
<h2 class="text-3xl font-bold text-center mb-8">{{ heading }}</h2>
</section>
Component-scoped CSS:
Write styles in the component's .css file. Use the component name as a namespace:
.hero-banner {
position: relative;
overflow: hidden;
}
.hero-banner__heading {
font-size: 2.5rem;
font-weight: 700;
}
This pattern applies when the user asks for a component that displays multiple repeated complex items -- e.g. "a grid of cards", "a testimonial carousel", "a pricing table with tiers", "a team members section".
When the component contains repeated items that are complex (more than one field per item), create TWO components:
items slotExample -- Card Grid (container) + Blog Card (item):
Container (card-grid.component.yml):
name: Card Grid
group: Organisms/Layout
props:
type: object
properties:
columns:
type: string
title: Columns
enum: ['2', '3', '4']
default: '3'
slots:
items:
title: "Card items"
Container Twig (card-grid.twig):
<div class="grid grid-cols-1 md:grid-cols-{{ columns }}">
{% block items %}{% endblock %}
</div>
Item (card-blog.component.yml):
name: Blog Card
group: Molecules/Content
props:
type: object
properties:
title:
type: string
title: Title
examples: ["Blog Post Title"]
excerpt:
type: string
title: Excerpt
examples: ["A short summary of the blog post."]
image:
type: object
title: Card Image
properties:
src:
type: string
alt:
type: string
width:
type: integer
height:
type: integer
examples:
- src: 'https://placehold.co/400x300'
alt: 'Blog image'
width: 400
height: 300
When to use this pattern:
When NOT to use this pattern:
items: { type: string }.When a component needs a third-party library (slider, lightbox, chart, animation, etc.), include them via libraryOverrides in the component.yml.
libraryOverrides:
js:
https://cdnjs.cloudflare.com/ajax/libs/Swiper/11.0.5/swiper-bundle.min.js: { }
css:
component:
https://cdnjs.cloudflare.com/ajax/libs/Swiper/11.0.5/swiper-bundle.min.css: { }
Key rules:
.min.js / .min.css)libraryOverrides.js with the full CDN URL as the key and { } as the valuelibraryOverrides.css.component with the full CDN URL as the key and { } as the valuelibraryOverrides:
js:
https://cdnjs.cloudflare.com/ajax/libs/Swiper/11.0.5/swiper-bundle.min.js: { }
slider.js: { attributes: { type: module } }
css:
component:
https://cdnjs.cloudflare.com/ajax/libs/Swiper/11.0.5/swiper-bundle.min.css: { }
hero-banner, card-product, pricing-table)components/ for similar names/descriptions. Avoid duplicates.examples for every prop.drush cr)components/ directorydrush cr)When reviewing SDC components, evaluate on these criteria (rate 1-10 each):
Common issues to check for:
examples in the YAML props -- they are used for preview rendering and documentationhttps://placehold.co/{width}x{height} as the srcgroup values in YAML (e.g., "Molecules/Marketing", "Organisms/Layout")Creating components:
Complex components: