AGENTS.md@packages/design-library · git:20260519.18ac812 · 2026-05-19 · sha256 860ff1b78a9c2000
AGENTS.md@packages/design-library git:20260519.18ac812A
Immutable. This exact content is served forever at /api/v1/blob/860ff1b78a9c2000.
# Design Library — Agent Instructions
Applies to all code under `packages/design-library/`. Subordinate to root [`AGENTS.md`](../../AGENTS.md).
## Component rules
1. **No `forwardRef`.** `forwardRef` is deprecated in React 19 — ref is now a
regular prop. Prefer `ComponentProps<"element">` over
`HTMLAttributes<HTMLElement>` because it includes element-specific props
(`href` for `<a>`, `type` for `<button>`, etc.) alongside ref. Exception:
polymorphic components that accept an `as` prop may use
`HTMLAttributes<HTMLElement>` + explicit `ref?: Ref<HTMLElement>` since
the element type is not fixed.
- Reference: [React 19 — ref as a prop](https://react.dev/blog/2024/12/05/react-19#ref-as-a-prop)
2. **`data-slot` on every root element.** Consumers can style components from
CSS without modifying the component source — e.g. `[data-slot="tag"] { ... }`.
Multi-part components add a slot per part (`data-slot="card"`,
`data-slot="card-header"`, etc.). This is the pattern shadcn/ui v4 adopted
for Tailwind v4 compatibility, where CSS-only overrides replace the old
`className` merging approach.
- Reference: [shadcn/ui v4 — data-slot](https://ui.shadcn.com/docs/changelog/2025-03-data-slot)
3. **Function declarations** for components (not arrow expressions or `const`
assignments). Function declarations are hoisted and keep component names
visible in stack traces and React DevTools, making debugging easier.
4. **Export variant functions** alongside components when using CVA (e.g.
`export { Tag, tagVariants }`). This lets consumers compose variant classes
in contexts where they don't render the component directly — e.g. applying
Tag's tone styles to a non-Tag element.
5. **No default exports.** Named exports only. Default exports allow silent
renames at import sites, which breaks refactoring and grep-ability.
6. **Single-file components.** Variants, types, and helpers are tightly coupled
to the component's rendering logic — splitting them across files adds
indirection without benefit. This matches the shadcn/ui convention where
even multi-part components (Card with CardHeader, CardBody, etc.) live in a
single file. Only break into a directory when the file exceeds 300 lines
with multiple independently useful subcomponents.
7. **Customization via props, not wrappers.** When a component needs
domain-specific behavior (e.g. custom link rendering), expose a callback
or component prop with a sensible default. Consumers inject behavior at
the call site. This follows the patterns used by
[react-markdown](https://github.com/remarkjs/react-markdown#components)
(`components` prop),
[MUI](https://mui.com/material-ui/integrations/routing/) (`component`
prop), and [Radix](https://www.radix-ui.com/docs/primitives/guides/composition)
(`asChild`). Domain convenience wrappers are the app layer's
responsibility — not the design library's.
## Review checklist
When reviewing PRs that add or modify design library components, verify:
- [ ] No `forwardRef` usage — ref is destructured from props
- [ ] `data-slot` attribute on every component root element
- [ ] `ComponentProps<"element">` used instead of `HTMLAttributes<HTMLElement>` (for element-specific props + ref) — exception: polymorphic `as` components
- [ ] Component uses function declaration, not `const` + arrow
- [ ] CVA-based components export their variants function
- [ ] No string interpolation for Tailwind classes
- [ ] `.js` extension on all relative imports (NodeNext resolution)
## Commands
```bash
cd packages/design-library && bun run typecheck # Type-check
```
## Dependencies
- Use `bun add --exact` for all dependencies (enforced by root bunfig.toml).
- Peer dependencies use `>=` ranges.
- All deps must have MIT-compatible licenses.