本文へ移動
cccskills
無料GitHub で公開

component-composition

Use on every UI change - Atomic Design levels, reuse-before-build, correct placement, and import direction through the shared component library.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md7.6 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Component Composition (Atomic Design)

Overview

All web UI follows Atomic Design on top of a shared component library. The quality bar is reuse and correct placement: a new screen is assembled from existing atoms and molecules, and anything genuinely new is added at the right level so the next screen reuses it too.

Core principle: Reuse before you build, and place new components at the level the import-direction rule expects — ui → atoms → molecules → organisms → templates → pages.

No design system yet in this repo (no tokens, no components/ levels, no INVENTORY.md)? Lay the foundation with web-design-system-foundation first — this skill assumes it already exists.

The Levels

LevelWhatWeb examples
ui/Vendor layer: generated/wrapped Radix-shadcn primitivesDialog, Popover, Tabs, Tooltip
AtomSmallest reusable UI, no app logic, variants onlyButton, Input, Label, Badge, Icon, Heading, Text, Container, Stack, Link
MoleculeA few atoms as one reusable unitFormField (label+input+error), NavLink, PriceTag, Rating, SearchBar
OrganismA page section composed of molecules/atoms (may contain another organism)SiteHeader, MobileNav, PricingTable, ContactForm, SiteFooter
TemplatePage skeleton: owns the grid + breakpoints, no dataMarketingLayout, DashboardLayout
PageRoute component: data + state wiring, composes templates/organismsPricingPage, ProjectBoardPage

The reuse procedure (every time, before writing a component)

  1. Read src/components/INVENTORY.md.
  2. Grep the level folders for the noun (grep -ri button src/components).
  3. Found a close match → reuse it, or extend it with a new variant backward-compatibly (add a cva variant, don't change an existing one's output).
  4. Nothing close → create it at the right level (see placement below) and add its INVENTORY.md line in the same commit.

Placement decision list

  • Does it fetch data or own app state? → page (or a container that wraps a page-level hook).
  • Is it a page skeleton with no content, owning only the grid/breakpoints? → template.
  • Several molecules/atoms forming a page section (pricing grid, contact form, header)? → organism.
  • Label + input + error, or icon + text pairing — two or three atoms as one reusable unit? → molecule.
  • A single element with variants and no composition (one button, one badge)? → atom.
  • A generated/wrapped Radix or shadcn primitive with no app-specific variants of its own? → ui/.

Import direction

ui ← atoms ← molecules ← organisms ← templates ← pages. A level imports only from levels to its left, plus lib/. Same-level imports are allowed ONLY for organisms (an organism may contain another organism). hooks/ and api/ are imported only by pages/. Where the repo runs ui-guard (from web-design-system-foundation), it enforces this on every build — a violation fails npm run build, it isn't a style note.

Atom API rules

  • No outer margin or absolute positioning — the parent lays out with gap-*; an atom that sets its own margin breaks every layout that reuses it.
  • Variants through cva, never a pile of boolean props; className is merged last via cn() and callers use it for layout only (width, grid placement, alignment) — never to restyle the atom; a new look is a new variant.
  • Every interactive state is styled: hover, focus-visible, active, disabled, aria-invalid, loading where relevant.
  • Accepts ref as a plain prop (React 19) or forwardRef (React 18) — a shared atom that can't take a ref breaks the first caller that needs to measure or focus it.

Composition over prop explosions

Three or more isX booleans on one component is a sign it's actually two components, or that it needs children/named slots instead. Prefer:

// ❌ boolean-prop explosion
<Card isHighlighted isCompact hasFooter footerText="Save" />

// ✅ composition: the variant is a real prop, content is children/slots
<Card variant="highlighted" size="compact">
  <Card.Footer>Save</Card.Footer>
</Card>

An explicit variant component (PrimaryCard vs <Card variant="primary">) is fine when the two really don't share markup — don't force one component to branch internally just to avoid two small ones.

Templates and organisms are container-aware

A template owns the grid and the breakpoints (sm:/md:/lg: live here) — organisms placed inside it should not assume a specific viewport width. Where an organism's internal layout depends on the space it's given rather than the screen, use a @container query or let the parent grid/flex sizing drive it, so the same organism works in a full-width template and a narrower sidebar slot.

Existing repos

Map the repo's own folders onto these levels (e.g. components/common/ ≈ atoms+molecules) and follow them as found. Never restructure an existing repo's component layout inside a feature task — if the mapping is genuinely broken, propose a follow-up task instead of doing it inline.

Changing a shared component

Grep every caller first (grep -r "from '@/components/atoms/Button'" src). Keep the change backward-compatible (new optional prop, new variant) or update every caller in the same task — never leave some callers on an old, incompatible shape. Update INVENTORY.md if the component's variants/props changed. npm run build must stay green.

Worked Example

Task: "add a pricing section to the marketing site."

  1. Read INVENTORY.md, grep components/atoms → Button, Badge, Heading already exist. Reuse them.
  2. Nothing in molecules/ prices a plan → new molecule PriceTag (amount + interval) and molecule PlanCard (Heading + PriceTag + Text + Button, props in, onSelect callback out).
  3. Nothing in organisms/ lists several plans → new organism PricingTable (grid of PlanCard, grid-cols-1 sm:grid-cols-2 lg:grid-cols-3, container-aware, no data fetching).
  4. PricingPage (page) loads the plan list, wires onSelectPlan, and composes MarketingLayout (template, already exists) around PricingTable.
  5. Add three INVENTORY.md lines (PriceTag, PlanCard, PricingTable) in the same commit, each with a co-located RTL test (see component-testing).

Only PriceTag, PlanCard, and PricingTable are new; Button, Badge, Heading, and MarketingLayout are pure reuse.

Common Mistakes

  • Rebuilding an existing atom/molecule inline instead of importing it (always grep first).
  • A component that fetches data or reads a global store below the page level — split presentation from data.
  • An atom with its own margin-* or position: absolute.
  • Boolean-prop explosions (isX, isY, isZ) instead of a variant prop or composition.
  • An organism that hardcodes md:/lg: assuming it's always full-width — breaks the day it's reused in a sidebar.
  • Changing a shared component's props without grepping every caller.
  • A component file long enough that you scroll to read it (~150 lines is the point to split).

Red Flags

  • Two screens render visually identical controls built two different ways.
  • A hex color or raw Tailwind palette class (bg-blue-500) inside a component — ui-guard, where it runs, fails the build on this.
  • A molecule or organism importing a hook from hooks/ or a client from api/.
  • A new component added with no INVENTORY.md line.
  • A file over ~150 lines that's still growing.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

Use when deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

makifbaysal のスキルをすべて見る

このスキルの問題を報告する