Skip to content
Development
Skill

/meta-design-composable-components

Composable component APIs — parts, state, polymorphism

From plugin
agents-inc-skills
24200 skills
Install
$ npx -y skills add agents-inc/skills --skill meta-design-composable-components --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/meta-design-composable-components

Context preview

The summary Claude sees to decide when to auto-load this skill.

Composable component APIs — parts, state, polymorphism

SKILL.md

meta-design-composable-components.SKILL.md
name: meta-design-composable-components
description: Composable component APIs — parts, state, polymorphism

Composable Components

> **Quick Guide:** Design component APIs the way headless primitive libraries do: a component owns behavior, state and accessibility -- the consumer owns markup and styling. Split configuration props into compound parts sharing scoped context, support controlled and uncontrolled use from the same API, let consumers substitute the rendered element (`asChild` or `render`), expose every state as a `data-*` attribute, and compose -- never replace -- the props, refs and handlers you receive. This is an alignment skill: run any existing component through the checklist at the end and fix what fails.

---

<critical_requirements>

CRITICAL: Before Using This Skill

> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)

**(You MUST express variation as parts and children, NOT as configuration props -- a new visual requirement must be satisfiable by rearranging JSX, never by adding a boolean or a `renderX` prop)**

**(You MUST ship the full state triple for every piece of component state -- `value` + `defaultValue` + `onValueChange` -- and NEVER copy a controlled prop into internal state)**

**(You MUST compose props, event handlers and refs that arrive from the consumer, NEVER replace them -- the consumer's handler runs first and must be able to suppress your internal behavior)**

**(You MUST expose state as `data-*` attributes on every part and keep behavior parts visually unopinionated -- no default classNames, no inline colors, no baked-in transitions)**

**(You MUST read the component's current API and all of its call sites before changing it -- alignment is a refactor of a contract, and every consumer is part of that contract)**

</critical_requirements>

---

**Auto-detection:** compound components, component API design, asChild, Slot, render prop, useRender, mergeProps, controlled uncontrolled, defaultValue, onValueChange, data-state, data attributes, headless component, primitive component, forwardRef, prop forwarding, composeRefs, composeEventHandlers, context scoping, roving tabindex, typeahead, focus trap, polymorphic component, children as composition, boolean prop explosion

**When to use:**

  • Designing the public API of a new reusable component
  • Aligning an existing component that has accumulated configuration props, booleans or `renderX` props
  • Deciding whether a new requirement becomes a prop, a part, or a slot
  • Adding controlled/uncontrolled duality to a component that only supports one mode
  • Making a component polymorphic so consumers can swap the rendered element
  • Moving styling decisions out of a component and into the consumer's stylesheet
  • Wiring accessibility structurally (ids, roles, focus, keyboard) instead of per-consumer
  • Reviewing a component library PR for API shape and forwarding discipline

**When NOT to use:**

  • One-off application components rendered in exactly one place with no reuse pressure
  • Layout containers that genuinely take no state and no variation
  • Deciding _which_ primitive library to adopt -- this skill is about API shape, not tool selection
  • Visual design decisions: spacing scales, color systems, variant naming

**Key patterns covered:**

  • Compound components over configuration props
  • Controlled/uncontrolled duality and the change-details object
  • Polymorphism: `asChild` + Slot, and the `render` prop + `useRender`
  • State as `data-*` attributes; zero visual opinions in behavior parts
  • Prop forwarding discipline: rest-spread, ref forwarding, handler composition
  • Context scoping and clear out-of-Root errors
  • Structural accessibility: id wiring, focus management, roving tabindex, typeahead
  • Children as composition, not `items={[...]}` configuration

---

Detailed Resources

  • [examples/core.md](examples/core.md) - Compound parts, children-as-composition, context scoping, the collection/registry problem
  • [examples/state-contract.md](examples/state-contract.md) - Controlled/uncontrolled hook, change details with reason and cancelation, state as data attributes
  • [examples/polymorphism.md](examples/polymorphism.md) - `asChild`/Slot, `render`/`useRender`, `composeRefs`, `composeEventHandlers`, merge rules
  • [examples/accessibility-structure.md](examples/accessibility-structure.md) - Id wiring, focus trap and restore, roving tabindex, typeahead
  • [reference.md](reference.md) - Prop-to-part translation, part and state naming, attribute vocabulary, ARIA and keyboard contracts

---

<philosophy>

Philosophy

A composable component draws one line and never crosses it:

> **The component owns behavior, state and accessibility. The consumer owns markup, element type and styling.**

Every defect this skill addresses is the same defect: the component reached across that line, and the API grew a prop to compensate. `showCloseButton` exists because the component decided to render a close button. `padding="lg"` exists because the component decided on spacing. `renderItem` exists because the component decided on item markup. Each one is a small piece of the consumer's job that the component took, then had to hand back through a narrow hole.

Composability is the opposite move: give the job back entirely. A `Dialog.Close` part is not a smaller `showCloseButton` -- it is the consumer rendering their own button, anywhere in the tree, with the close behavior attached to it.

**The two current expressions of one principle.** Element substitution is the clearest case of the line being respected, and two shapes for it are current:

| Expression | Shape | Merging | | ----------------- | -------------------------------------------------- | ------------------------------------------------- | | `asChild` + Slot | `<Trigger asChild><a href="

Read more
Ships withagents-inc-skills

The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?

Get the whole plugin

Other skills on agents-inc-skills.