Reuse behavior without losing control
Choose and adapt a component library by ownership, interaction quality, customization cost, and maintenance.
Why this matters
A library can save you from rebuilding tricky interaction behavior. It still has to fit your product, your component edges, and how you maintain code.
What to understand
Know what you receive and what stays yours: headless primitives give you behavior and semantics while you own composition and verification; copied source gives you code while you own local changes and upstream fixes; styled components give you a visual baseline while you own theme fit and upgrades.
Before adding anything, find your existing wrappers, token mappings, form controls, overlays, and layout shells. Use the component you already have if it solves the behavior.
Watch for
- Replacing a primitive's required DOM or dropping required parts and breaking accessibility.
- A second library bringing competing focus managers, portals, style resets, and theme habits.
- Wrapping just to rename every prop with no product rule added.
- Feature logic baked into a generic piece because only one feature uses it today.
- Selectors tied to generated class order or inner DOM breaking across upgrades.
- Assuming every install matches the docs instead of checking what your repo uses.
Strong default
Try the component in the hard case first: a menu inside a dialog, a long crew list, a narrow form. Ask your agent to check keyboard behavior and screen-reader naming before you spend time on visual styling. Customize through tokens, documented slots, variants, and component APIs.
When this doesn't apply
Headless doesn't mean "renders nothing" — a primitive may render the DOM and attributes its behavior needs. Copied code deliberately changed is fine, but note why it differs and how upstream fixes reach it.
In practice
| Model | What you receive | What remains your responsibility |
|---|---|---|
| Headless primitives | Behavior, semantics, and unstyled rendered elements. | Composition, styles, content, integration, and verification. |
| Copied source | Component code committed into your repository. | Local changes and applying relevant upstream fixes. |
| Styled components | A visual baseline and supported theme/customization APIs. | Theme fit, supported variations, and upgrade compatibility. |
A thin product wrapper can set approved tokens and variants while keeping the primitive's agreement intact. A feature piece then adds product behavior on top.
Dialog primitive focus and modal interaction
Product Dialog surface, spacing, title and action conventions
Invite dialog recipient, role, validation and request state
Server operation permission, persistence and delivery contractThe current shadcn/ui documentation describes its source distribution and component choices. Check what your repo actually uses instead of assuming every install has the same underlying primitive.
Verify
Labels, focus entry and return, dismissal, scrolling, long content, themes, and reduced motion where they apply. A library's accessibility work doesn't prove your wiring is accessible: a missing label or wrong trigger can still block the task.
Related skills
Use $system to inspect duplication and drift; $component to define the boundary of a needed extension. Design tokens explains the shared visual contract.
Last updated on