Component Reuse First
Before creating any UI component, exhaustively check whether an existing component (or close variant) already covers the need. Only create a new component when reuse is genuinely impossible — and when you do, design it to be reused next time.
Core Workflow
1. Search Before Create (mandatory)
Run all of these in parallel before writing any new component:
- Glob common component directories:
**/components/**/*.{tsx,jsx,ts,js,vue,svelte}
**/ui/**/*.{tsx,jsx,vue,svelte}
**/shared/**/*.{tsx,jsx,vue,svelte}
**/design-system/**/*, **/lib/components/**/*
- Grep for the conceptual name and synonyms:
- User asks for "Modal" → grep
Modal|Dialog|Popup|Overlay|Sheet|Drawer
- User asks for "Button" → grep
Button|Btn|IconButton|CTA
- User asks for "Card" → grep
Card|Panel|Tile|Box
- User asks for "Input" → grep
Input|TextField|TextInput|FormField
- User asks for "List" → grep
List|Table|DataGrid|Items
- Check imports in similar pages/features for what they already use
- Check the package.json for design system libraries (shadcn/ui, MUI, Chakra, Mantine, Ant, Radix, HeroUI, NextUI, Tamagui, native-base, etc.) — prefer those over hand-rolling
2. Decision Tree
After search:
- Exact match exists → Reuse as-is. Do not duplicate.
- Close match exists (90%+) → Extend the existing component via props/variants. Do not fork.
- Partial match exists → Refactor existing into base + variant, or compose. Avoid copy-paste.
- Nothing matches → Create new, following the Reusable-by-Default rules below.
State the decision explicitly to the user before coding: e.g. "Found Button at src/ui/Button.tsx with variant prop — adding ghost variant" or "No matching modal — creating new Modal at src/ui/Modal.tsx."
3. Reusable-by-Default Rules (when creating new)
When a new component is necessary, build it for the next caller, not just this one:
Placement
- Shared/generic →
components/ui/, src/ui/, or the project's design-system path
- Feature-scoped (only meaningful inside one feature) →
features/<feature>/components/
- Never put a reusable primitive inside a route/page file
API design
- Accept
className and forward refs (React: forwardRef + cn(className) pattern)
- Spread rest props to the underlying element (
...props / v-bind="$attrs")
- Use variants (e.g.
cva, tv, prop unions) instead of duplicating components
- Children/slots over hardcoded content
- Use semantic prop names (
variant, size, tone, intent) — not visual ones (bigBlueButton)
- Required vs optional props: keep required surface minimal; sensible defaults for the rest
Composition over configuration
- Prefer compound components (
Card.Header, Card.Body) over giant prop bags
- Slot/children patterns beat dozens of
*Content props
Styling
- Match the project's existing approach (Tailwind, CSS modules, styled-components, vanilla-extract). Do not introduce a new styling system.
- Use design tokens / theme values, not hard-coded colors or spacings
Type safety (TS projects)
- Extend native element props:
ButtonHTMLAttributes<HTMLButtonElement>
- Discriminated unions for variants when behavior differs (e.g.
as="link" | "button")
Accessibility
- Correct semantic element by default (button vs div)
- ARIA attributes wired through props
- Keyboard interaction handled at the primitive level
4. After Creating
- Export from the directory's
index.ts barrel (if the project uses one)
- Add to Storybook / docs if the project has them
- If you noticed during search that several existing components could now be replaced by the new one, mention it to the user (don't refactor unprompted)
Anti-patterns to Refuse
- ❌ Creating
Button2, NewButton, CustomButton next to existing Button
- ❌ Inline-defining a component inside a page when it's clearly reusable
- ❌ Copy-pasting a component to tweak two lines instead of adding a prop
- ❌ Hardcoded copy/colors/sizes that prevent reuse
- ❌ Introducing a second design system / UI lib when one is already in use
- ❌ Skipping the search step "because the component is simple"
Quick Heuristics
- If you typed
function Button( and a Button already exists in the repo → stop, reuse.
- If your new component has zero props → it's probably not reusable; ask if it should accept content/variants.
- If you're about to write the same JSX you saw 20 minutes ago in another file → extract it.
Example Interactions
User: "Add a confirmation modal for the delete action."
You: Grep for Modal|Dialog|Confirm. Found ConfirmDialog at src/ui/ConfirmDialog.tsx. → Reuse it; pass title, onConfirm, destructive props.
User: "Create a pricing card component."
You: Grep for Card. Found Card primitive in src/ui/Card.tsx. → Compose PricingCard from Card + Card.Header + Card.Body; place in features/pricing/components/. Don't reinvent the card frame.
User: "I need a button with a loading spinner."
You: Grep for Button. Found one without loading prop. → Add loading?: boolean prop to existing Button; do not create LoadingButton.
Activation Triggers
This skill should activate whenever the conversation involves:
- Creating, building, scaffolding, or adding a UI component
- Words: component, button, modal, dialog, card, form, input, table, list, dropdown, menu, sidebar, header, footer, layout, page, view, screen, widget
- Frameworks: React, Vue, Svelte, Angular, Solid, SwiftUI, Jetpack Compose, Flutter
- Phrases: "make a", "build a", "I need a", "create a", "add a" + UI noun
1---2name: component-reuse-first3description: Search existing components before creating new ones. When a new component is unavoidable, design it for future reuse with proper props, composition, and placement in shared directories. Use when building UI, creating React/Vue/Svelte/Angular/SwiftUI components, adding buttons/forms/cards/modals/tables, scaffolding pages, or any time the user says "create a component", "add a component", "build a UI", or mentions component-like work.4---56# Component Reuse First78Before creating any UI component, exhaustively check whether an existing component (or close variant) already covers the need. Only create a new component when reuse is genuinely impossible — and when you do, design it to be reused next time.910## Core Workflow1112### 1. Search Before Create (mandatory)1314Run all of these in parallel before writing any new component:1516- **Glob** common component directories:17 - `**/components/**/*.{tsx,jsx,ts,js,vue,svelte}`18 - `**/ui/**/*.{tsx,jsx,vue,svelte}`19 - `**/shared/**/*.{tsx,jsx,vue,svelte}`20 - `**/design-system/**/*`, `**/lib/components/**/*`21- **Grep** for the conceptual name and synonyms:22 - User asks for "Modal" → grep `Modal|Dialog|Popup|Overlay|Sheet|Drawer`23 - User asks for "Button" → grep `Button|Btn|IconButton|CTA`24 - User asks for "Card" → grep `Card|Panel|Tile|Box`25 - User asks for "Input" → grep `Input|TextField|TextInput|FormField`26 - User asks for "List" → grep `List|Table|DataGrid|Items`27- **Check imports** in similar pages/features for what they already use28- **Check the package.json** for design system libraries (shadcn/ui, MUI, Chakra, Mantine, Ant, Radix, HeroUI, NextUI, Tamagui, native-base, etc.) — prefer those over hand-rolling2930### 2. Decision Tree3132After search:3334- **Exact match exists** → Reuse as-is. Do not duplicate.35- **Close match exists (90%+)** → Extend the existing component via props/variants. Do not fork.36- **Partial match exists** → Refactor existing into base + variant, or compose. Avoid copy-paste.37- **Nothing matches** → Create new, following the Reusable-by-Default rules below.3839State the decision explicitly to the user before coding: e.g. "Found `Button` at `src/ui/Button.tsx` with `variant` prop — adding `ghost` variant" or "No matching modal — creating new `Modal` at `src/ui/Modal.tsx`."4041### 3. Reusable-by-Default Rules (when creating new)4243When a new component is necessary, build it for the next caller, not just this one:4445**Placement**46- Shared/generic → `components/ui/`, `src/ui/`, or the project's design-system path47- Feature-scoped (only meaningful inside one feature) → `features/<feature>/components/`48- Never put a reusable primitive inside a route/page file4950**API design**51- Accept `className` and forward refs (React: `forwardRef` + `cn(className)` pattern)52- Spread rest props to the underlying element (`...props` / `v-bind="$attrs"`)53- Use **variants** (e.g. `cva`, `tv`, prop unions) instead of duplicating components54- Children/slots over hardcoded content55- Use semantic prop names (`variant`, `size`, `tone`, `intent`) — not visual ones (`bigBlueButton`)56- Required vs optional props: keep required surface minimal; sensible defaults for the rest5758**Composition over configuration**59- Prefer compound components (`Card.Header`, `Card.Body`) over giant prop bags60- Slot/children patterns beat dozens of `*Content` props6162**Styling**63- Match the project's existing approach (Tailwind, CSS modules, styled-components, vanilla-extract). Do not introduce a new styling system.64- Use design tokens / theme values, not hard-coded colors or spacings6566**Type safety (TS projects)**67- Extend native element props: `ButtonHTMLAttributes<HTMLButtonElement>`68- Discriminated unions for variants when behavior differs (e.g. `as="link" | "button"`)6970**Accessibility**71- Correct semantic element by default (button vs div)72- ARIA attributes wired through props73- Keyboard interaction handled at the primitive level7475### 4. After Creating7677- Export from the directory's `index.ts` barrel (if the project uses one)78- Add to Storybook / docs if the project has them79- If you noticed during search that *several* existing components could now be replaced by the new one, mention it to the user (don't refactor unprompted)8081## Anti-patterns to Refuse8283- ❌ Creating `Button2`, `NewButton`, `CustomButton` next to existing `Button`84- ❌ Inline-defining a component inside a page when it's clearly reusable85- ❌ Copy-pasting a component to tweak two lines instead of adding a prop86- ❌ Hardcoded copy/colors/sizes that prevent reuse87- ❌ Introducing a second design system / UI lib when one is already in use88- ❌ Skipping the search step "because the component is simple"8990## Quick Heuristics9192- If you typed `function Button(` and a `Button` already exists in the repo → stop, reuse.93- If your new component has zero props → it's probably not reusable; ask if it should accept content/variants.94- If you're about to write the same JSX you saw 20 minutes ago in another file → extract it.9596## Example Interactions9798**User:** "Add a confirmation modal for the delete action."99**You:** Grep for `Modal|Dialog|Confirm`. Found `ConfirmDialog` at `src/ui/ConfirmDialog.tsx`. → Reuse it; pass `title`, `onConfirm`, `destructive` props.100101**User:** "Create a pricing card component."102**You:** Grep for `Card`. Found `Card` primitive in `src/ui/Card.tsx`. → Compose `PricingCard` from `Card` + `Card.Header` + `Card.Body`; place in `features/pricing/components/`. Don't reinvent the card frame.103104**User:** "I need a button with a loading spinner."105**You:** Grep for `Button`. Found one without `loading` prop. → Add `loading?: boolean` prop to existing `Button`; do not create `LoadingButton`.106107## Activation Triggers108109This skill should activate whenever the conversation involves:110- Creating, building, scaffolding, or adding a UI component111- Words: component, button, modal, dialog, card, form, input, table, list, dropdown, menu, sidebar, header, footer, layout, page, view, screen, widget112- Frameworks: React, Vue, Svelte, Angular, Solid, SwiftUI, Jetpack Compose, Flutter113- Phrases: "make a", "build a", "I need a", "create a", "add a" + UI noun