@ship-it-ui/ui
v0.0.3
Published
React component library for the Ship-It design system. Tailwind v4 + Radix UI primitives, themed via @ship-it-ui/tokens.
Downloads
212
Maintainers
Readme
@ship-it-ui/ui
The React component library for the Ship-It design system.
How this fits in
Part of the Ship-It Design System. See the
architecture overview for how @ship-it-ui/tokens, @ship-it-ui/icons,
@ship-it-ui/ui, and @ship-it-ui/shipit compose.
Architecture
src/
├── components/ Atomic components (Button, Input, Avatar, Dialog, …)
│ └── Button/
│ ├── Button.tsx Component + cva variant definitions
│ ├── Button.stories.tsx Storybook stories (also serve as autodocs)
│ ├── Button.test.tsx Vitest + Testing Library + vitest-axe
│ └── index.ts Re-exports the component + types
├── patterns/ Composites of components (Tabs, Combobox, DataTable, …)
├── hooks/ useEscape, useOutsideClick, useTheme, useDisclosure,
│ useControllableState, useKeyboardList
├── utils/
│ └── cn.ts clsx + tailwind-merge
├── styles/
│ ├── globals.css Tailwind v4 entrypoint + token CSS-var bridge
│ └── animations.css Keyframes (spin, pulse, indeterminate, dialogIn, …)
├── test/
│ └── setup.ts Vitest global setup (jsdom polyfills + vitest-axe)
└── index.ts Public API barrel — only re-exportsComponent anatomy
Every component follows the same shape — open Button/ to see the canonical example:
| File | What it contains |
| --------------- | ------------------------------------------------------------- |
| Component.tsx | The implementation. Variants via cva. Tokens via Tailwind. |
| *.stories.tsx | One story per variant + a "Sizes" / "States" composite story. |
| *.test.tsx | Render, interaction, and axe a11y tests. |
| index.ts | Re-exports the component and any related types. |
Adding a new component
See docs/adding-a-component.md for the
step-by-step guide. In short:
- Copy
src/components/Button/and rename to your component. - Replace the implementation, story, and tests.
- Add a re-export line to
src/index.ts. pnpm --filter @ship-it-ui/ui test— make sure tests pass and axe is clean.- Run Storybook (
pnpm dev) and visually verify. pnpm changeset— describe the new component as aminorbump.
Conventions
- Always consume semantic tokens, never primitive ones.
bg-accent, notbg-indigo-600. - Forward refs. Every component uses
forwardRefso consumers can attach refs and Radix integrations can wire focus management. asChildpolymorphism. Use@radix-ui/react-slotfor components that should be able to render as a different element (e.g., aLink).- A11y is non-negotiable. Tests assert
axeviolations === 0. Use@testing-library/user-event(notfireEvent) so interactions match real user input. - Styling: Tailwind classes consuming token CSS variables. Keep all variant logic
inside
cva— no inline conditional classNames in JSX.
