Design module composition
Skill jacob-balslev/skill-graph/marketplace/skills/design-module-composition
Use when designing reusable component modules — composition patterns, compound components, slot/children APIs, render props, headless component contracts, and the choice between configuration and composition. Do NOT use for application-level architecture, single-use feature components, or visual styling decisions. Do NOT use for Choose the border radius value for cards. Do NOT use for Decide where the OrderDetailPage component lives in the folder structure. Do NOT use for Pick the brand font for headings.From its SKILL.md
npx -y skills add jacob-balslev/skill-graph --skill design-module-compositionAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as CC-BY-4.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
10.5 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it
Design Module Composition
Concept of the skill
Design module composition is the discipline of shaping a reusable component's public API so that its variation is achieved by composing exposed parts rather than by configuring a growing set of props. A composable module externalizes its internals as a contract — most often through one of four mainstream patterns: compound components (a parent and a named set of children share context, like Tabs / Tabs.List / Tabs.Trigger / Tabs.Panel), slot/children APIs (named slots accept arbitrary content), render props or function-as-children (the parent supplies state and the consumer supplies markup), and headless primitives (state and behavior leave the module entirely as hooks or unstyled components, leaving all markup and styling to the consumer). The polymorphic "asChild"/"as" pattern lets a consumer swap the rendered element while inheriting behavior and ARIA wiring. The central design judgment is the trade between configuration and composition: a prop-heavy API is fast for the common case but brittle for unanticipated variants, while a composition API costs more typing up front and absorbs variants with no friction — which is why mature systems often offer both, a high-level summary component built on low-level composable primitives. The module's real API is the context contract between parent and children, not the prop signatures, so the discipline asks for every variation whether it belongs to the module's identity (make it a prop) or to how a specific consumer uses the module (make it a slot).
Coverage
A composable component module exposes its parts to consumers rather than hiding them behind a configuration prop. The four mainstream patterns are compound components (a parent and a named set of children share context: <Tabs>, <Tabs.List>, <Tabs.Trigger>, <Tabs.Panel>), slot/children APIs (named slots accept arbitrary content: <Card header={...} footer={...} />), render props or function-as-children (the parent provides state, the consumer provides markup: <Tooltip>{({open}) => ...}</Tooltip>), and headless primitives (state and behavior are exposed as hooks or unstyled components — Radix, Headless UI, TanStack Table — leaving all markup and styling to the consumer).
The "asChild" or polymorphic pattern (Radix's term; also called "as" prop, "render" prop in some libraries) lets a consumer change the rendered element while inheriting all behavior: <Dialog.Trigger asChild><Button>Open</Button></Dialog.Trigger>. The pattern collapses two-level wrappers and avoids the "button inside button" accessibility error, but requires the parent to clone or render-prop its single child carefully.
Choosing between configuration and composition is a trade-off between control surface and expressiveness. A prop-heavy API (<Card title={} subtitle={} action={} variant={} />) is fast to consume for the common case and friction-heavy for variants the original author didn't anticipate. A composition API (<Card><Card.Header>...</Card.Header></Card>) reverses this: more typing for the common case, no friction for variants. Mature design systems often offer both: a high-level "summary" component that consumes the low-level composable primitives.
State sharing between compound-component pieces uses React context (or framework-equivalent). The context contract — what the parent provides, what the children expect — is the real API of the module, and changing it is a breaking change even when the prop signatures stay the same. Headless primitives push this further: state and behavior leave the module entirely, and the visual layer is the consumer's responsibility.
Philosophy of the skill
Composition externalizes variation. Every boolean prop on a component is a decision the module author made on behalf of every future consumer; every slot is a decision deferred. The discipline is to ask whether the variant being added is part of the module's identity (it should be a prop) or part of how a specific consumer uses the module (it should be a slot).
Headless primitives separate three concerns that are routinely conflated: state (open/closed, selected, expanded), behavior (focus trapping, keyboard navigation, ARIA attribute wiring), and presentation (markup and styles). Conflation is convenient until the design system needs a second visual treatment of the same behavior; separation makes that addition trivial.
Verification
- The component's primary variations are achievable by composing children rather than passing boolean props; a count of boolean props is in single digits.
- Compound-component children render outside the parent only with an explicit error (they require the parent's context).
- Slot props accept ReactNode (or framework equivalent) rather than typed sub-shapes; consumers can pass any valid element.
- Accessibility wiring (aria-controls, aria-expanded, focus return on dialog close) is the module's responsibility, not the consumer's, even when markup is delegated via asChild or headless patterns.
- Documentation shows the compositional pattern as the primary example, with prop-API shortcuts noted as conveniences.
- Replacing the rendered element type via asChild or polymorphic-as preserves all behavior and ARIA attributes.
- The module has at least one example of being composed into a non-obvious shape (a tabs control becoming a vertical sidebar) without modification.
Do NOT Use When
- The component is single-use within one feature and will never be reused. Reach for the simpler prop-driven shape.
- The question is which features live in which folders or which application owns which screen. Use frontend-architecture.
- The decision is purely visual — color, spacing, type. Use visual-design-foundations or layout-composition.
- The work is configuring or publishing the shared library that hosts these modules. Use design-system-architecture.
- The concern is meeting specific accessibility criteria for a control pattern. Use a11y for the criteria; this skill for the API shape.
Skill Graph context
<!-- skill-graph-context:start (generated — do not edit by hand) -->Classification
- Subject:
design - Public:
true - Scope: Designing reusable component modules — composition patterns, compound components, slot/children APIs, render props, headless component contracts, and the configuration-vs-composition choice. Portable across any component-based UI; principle-grounded, not repo-bound. Excludes application-level architecture, single-use feature components, and visual styling decisions.
When to use
- Design a Dialog component whose trigger, content, and close button are addressable by consumers
- Refactor a Card with 14 boolean props into a composition-based API
- Build a headless table primitive that exposes state and behavior without imposing markup
- Triggers:
component module composition,composition over configuration,headless component,slot pattern,asChild
Not for
- Choose the border radius value for cards
- Decide where the OrderDetailPage component lives in the folder structure
- Pick the brand font for headings
Related skills
- Verify with:
a11y - Related:
design-system-architecture,frontend-architecture,interaction-patterns,a11y
Concept
- Mental model: |
- Purpose: |
- Boundary: |
- Analogy: A composable module is to its consumers what a set of LEGO bricks is to a builder — the value is the standardized studs (the context contract and slots) that let anyone assemble shapes the kit's designer never imagined, rather than a single pre-glued model with a few painted-on options; freezing it into one configured shape is gluing the bricks together.
- Common misconception: |
Keywords
component composition,compound components,slot api,headless components,render props,polymorphic components,asChild pattern,children as api,composition over configuration,component contract design
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.