Claude-skill-registry component-scaffolding
Generate Drupal/Twig component skeletons with web components and Miyagi validation. Use when user requests to create, scaffold, or add a new component at a specific path (e.g., "add component skeleton at patterns/share-button"), or when creating component files including Twig templates, CSS, JavaScript web components, JSON schemas, or mock data files.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/component-scaffolding" ~/.claude/skills/majiayu000-claude-skill-registry-component-scaffolding && rm -rf "$T"
skills/data/component-scaffolding/SKILL.mdComponent Scaffolding
Generate component skeletons for a Drupal theme using Twig, web components, and Miyagi for validation.
Trigger Phrases
- "Add component skeleton at patterns/..."
- "Create new component..."
- "Scaffold component..."
- Creating/updating schema.yaml or mocks.yaml files
Configuration
Component Library Root
This skill assumes it lives within a component library project, e.g.:
apps/component-library/ ├── .claude/ │ └── skills/ │ └── component-scaffolding/ ← this skill ├── src/ │ ├── components/ │ └── css/ └── <theme-name>.libraries.yml
The component library root is three levels up from this skill (i.e.,
../../.. relative to this SKILL.md).
Theme Name Discovery
The
<theme-name> placeholder must be replaced with the actual Drupal theme name. To determine it:
- Navigate to the component library root
- Find the
file — the filename prefix is the theme name*.libraries.yml - Example:
→ theme name iscircle_dot.libraries.ymlcircle_dot
If the theme name cannot be determined from existing files, ask the user.
File Templates
1. Twig Template: <component-name>.twig
<component-name>.twig{{ attach_library("<theme-name>/pattern-<component-name>") }} <div class="<ComponentName>"> {# Component implementation #} </div>
- Library name:
(kebab-case)pattern-<component-name> - CSS class:
(PascalCase)<ComponentName> - Single tab indentation
2. CSS: <component-name>.css
<component-name>.css/** @define <ComponentName>; */ .<ComponentName > { /* Component styles */ }
- PascalCase in
comment@define - Tab indentation
3. JavaScript: <component-name>.js
<component-name>.jsOnly create if explicitly needed. Skip if user says "no JavaScript", "CSS only", etc.
// @ts-check class <ComponentName> extends HTMLElement { constructor() { super(); } connectedCallback() { this.#addEventListeners(); } /** * Add event listeners */ #addEventListeners() { // Add event listeners here } } customElements.define("<component-name>", <ComponentName>);
- PascalCase class name
- NO prefix on custom element name (use kebab-case directly)
- Only
method in skeleton#addEventListeners() - NO
field or#elements
method#getElements()
4. Schema: schema.yaml
schema.yaml$schema: http://json-schema.org/draft-07/schema# $id: /<tier>/<component-name> type: object required: - property1 additionalProperties: false properties:
matches component tier path$id- Include
array with placeholder namesrequired - Leave
empty in skeletonproperties: - 2-space indentation (YAML standard)
For detailed schema patterns, see references/schema-and-mocks.md.
5. Mocks: mocks.yaml
mocks.yaml- Single blank line only in skeleton
- User adds their own mock data later
For mock data patterns, see references/schema-and-mocks.md.
6. CSS Entry Point: src/css/<component-name>.css
src/css/<component-name>.css@import url("../components/<tier>/<component-name>/<component-name>.css") layer(components);
Note: If the component is an element, you can use the
entry point instead.elements.css
7. Library Definition: <theme-name>.libraries.yml
<theme-name>.libraries.ymlAdd entry alphabetically within the appropriate tier section:
pattern-<component-name>: header: true css: component: build/assets/css/<component-name>.css: {} js: build/assets/components/<tier>/<component-name>/<component-name>.js: attributes: type: module
- Omit the
block entirely if no JavaScript file is createdjs: - Maintain blank line between library definitions
- Omit the
block entirely if the component is an elementcss:
Naming Conventions
| Item | Format | Example |
|---|---|---|
| Directory/files | kebab-case | |
| CSS class | PascalCase | |
| JS class | PascalCase | |
| Custom element | kebab-case, NO prefix | |
| Library name | | |
| Schema $id | | |
Component Tiers
| Tier | Location | Library Prefix |
|---|---|---|
| Elements | | |
| Patterns | | |
| Template Components | | |
| Templates | | |
Workflow
- Create component directory:
src/components/<tier>/<component-name>/ - Create component files (twig, css, schema.yaml, mocks.yaml, and js only if needed)
- Create CSS entry point:
src/css/<component-name>.css - Add library definition to
(alphabetically in tier section)<theme-name>.libraries.yml - Run linters to verify
Optional Files
Pay attention to user requests indicating which files to skip:
| User says | Action |
|---|---|
| "no JavaScript" / "CSS only" | Skip .js file, omit from library |
| "no CSS" / "JavaScript only" | Skip .css files, omit from library |
| "schema only" / "just the schema" | Create only schema.yaml |
Notes
- Skeletons provide structure, not functionality
- All files use tabs except YAML (2 spaces)
- Run linters after creation to verify