skills/canvas-component-composability/SKILL.md
Design Canvas-ready React components with slots and decomposition-first patterns. Use when (1) Designing a component's prop/slot structure, (2) A component is growing too large, (3) Deciding between props vs slots, (4) Refactoring monolithic components, (5) Modeling repeatable list/grid content, (6) Reusing, composing, or wrapping existing workspace components. Ensures Canvas compatibility.
npx skillsauth add drupal-canvas/skills canvas-component-composabilityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Prefer small, focused components over monolithic ones with many props. When a component starts accumulating many unrelated props, decompose it into smaller, composable pieces.
For repeatable card/list/grid UI, default to two Canvas components: a parent
layout component with a slot for the repeated children, and a child component
for one item. Do not flatten repeated items into numbered prop groups such as
car1Name, car2Name, feature1Title, or card3Image.
This skill owns the reusable modeling rules for:
For the canonical reuse-first policy, follow
canvas-component-definition. For
exact component.yml grammar and slot schema, follow
canvas-component-metadata.
When the task names existing components or clearly implies composition, start
with the reuse check in
canvas-component-definition
before creating a new component. This skill focuses on how components compose
once that boundary is clear.
Load references only as needed:
references/repeatable-content.mdreferences/repeatable-content.md ("Slot container minimum size" section)Slots are the primary mechanism for composability. Instead of passing complex
data through props, use slots to let parent components accept child components.
This matches how Canvas users build pages by placing components inside other
components. This is the design-time rubric to use before writing
component.yml.
| Use slots for | Use props for | | ------------------------------------- | ----------------------------------- | | Variable number of child components | Single, required values (text, URL) | | Content that users should compose | Configuration options (size, color) | | Complex nested structures | Simple data (strings, booleans) | | Content that varies between instances | Content consistent across instances |
Treat a single image as one prop, not as a slot and not as multiple URL/alt
props. If a component needs one image, use a semantic image prop such as image
or backgroundImage with the Canvas image schema ref.
For repeatable cards/items, the parent usually owns layout props such as heading, intro text, alignment, or column count, while each child owns item content props such as title, image, price, label, CTA, or metadata.
Repeatable rich items should use the parent-slot-plus-child-component pattern,
not array-of-object props. See references/repeatable-content.md.
Apply the rubric to blocks this way: presets and simple copy stay in props; grids of cards, tab panels, footer columns, or swappable regions belong in slots or nested child components with their own slots. Do not encode large composed regions as string props or JSON blobs.
Use one primary modeling style per component. Sometimes a hybrid is valid: one
variant plus one or two orthogonal toggles.
Variants are the default:
variant enum selects named presets whose values imply a bundle of
styles and structure rules.variant enum when the design has named presets or when many
arbitrary combinations would be invalid.variant as the prop ID for the main preset field instead of synonyms
like appearance or layoutVariant.size or density only when those axes are
independently meaningful.Granular props are appropriate when:
Hybrid modeling is acceptable, but avoid a large pile of independent knobs when the design really describes a small set of named presets.
| Situation | Favor | | ---------------------------------------------------------- | ------------------------ | | Mutually exclusive layouts (A or B, not mix-and-match) | Variants | | Design uses named presets or Figma variants | Variants | | Many combinations would be invalid or untested | Variants | | Product needs arbitrary mixing of orthogonal toggles | Granular (or hybrid) | | User asks for separate controls per axis | Granular |
Document the choice in the decomposition handoff so implementation and
component.yml stay aligned.
Match the decomposition handoff and component.yml order so Canvas editors see
a sensible form flow.
variant and list it first.When there is no primary variant, list content props first and configuration
after.
If there is no single variant but the model is otherwise preset-oriented,
still put the dominant preset enum first when it exists.
canvas-component-metadata.Replace these with slot-plus-child-component composition.
In those cases, consider whether the parent should own that markup or use a narrow prop instead.
Declare slots in component.yml and render them as named props in JSX.
For exact slot schema and constraints (map vs [], slot keys, children
handling), follow canvas-component-metadata as the source of truth.
Use these heuristics when auditing whether a component boundary is too coarse or too fine. Use them after an initial tree and prop/slot sketch exist. The goal is that editors can reason about each component and instances can reuse without copy-paste props.
Consider breaking up a component when it has:
machineName owning unrelated concernsitem1Title, item2Title, item3Title)showX/showY chains that encode which children exist instead of letting
authors place children directlyElements that appear on many pages but are not always needed together should be separate components.
When the same combination of elements is repeated, extract it:
article-metaresource-covermetadata-itemicon-linkcard-grid + cardfeatured-cars-grid + car-cardDo not bake two-column or grid layouts into content components. Use layout components and compose content into them.
Extract a child component, or add a slot, when any of these are true:
Typical extractions: Meta, Actions, Media, Nav, and item components for
lists or grids.
Keep components together when:
div: every flex child becomes a slot without giving authors real
control. Group by meaningful composition boundaries.Terms like atom, molecule, and organism can describe scale, not a mandate. Prefer reuse, editor control, and Canvas constraints over strict atomic-design tiers.
testing
Use for any task touching site chrome — header, footer, sidebar, or global navigation that repeats across pages — and for any region-spec work (create, modify, review, validate region JSON, or the project-level layout component). Also load when a task creates or edits multiple pages that share chrome, or asks for a "site" or "navigation between pages"; shared chrome belongs in regions, never inlined into page JSON.
content-media
Create and modify content templates that map Drupal content entities to Canvas component layouts. Use when asked to (1) Create a new content template, (2) Modify an existing content template, (3) Add or change entity field mappings in a template, (4) Compose components in a content template via slots. Content templates live in the configured `contentTemplatesDir` (default `content-templates/`) and define how Drupal entity types, bundles, and view modes render as Canvas component trees.
tools
Plans and builds Drupal Canvas navigation UI (main nav, footer links, sidebar nav, mobile drawers, breadcrumbs) using design decomposition for structure and props/slots, then JSON:API menu or page-context patterns from canvas-data-fetching. Use when the user asks for navigation, header or footer links, menus, menu_items, mobile nav, or breadcrumb trails. Run after canvas-design-decomposition for layout and API sketches; follow canvas-data-fetching for SWR, JsonApiClient, sortMenu, and menu fallbacks.
development
Plans structure for a component library with props/slots and right-sized component granularity. Run before building or adding Canvas components (new `src/components/` folders, component.yml, React), or for plan-only / breakdown-only work, whenever UI must map to a coherent tree. Mandatory for every new Figma frame or greenfield screen—repository drafts do not replace phases A–G.