Component
Where UI lives in the SHOPin storefront accelerator presentation app, how it ties to Feature folders, and how to document and test it.
Workspaces
apps/presentation— Shared UI undercomponents/; feature UI underfeatures/(see Feature).apps/storybook— Stories for shared UI (e.g.src/stories/ui/).core/contracts— Shared types (no UI).core/i18n— Translation data and helpers.
Pick the location
- Generic / reusable UI —
components/ui/: buttons, inputs, dialogs, cards, and other design-system pieces used across features. - Layout / shell —
components/layout/: header, footer, top bar, locale switcher, and other app shell pieces. - Feature-only — Under
features/<name>/(optionalcomponents/inside the feature). Import from the feature root only from outside that feature—see Feature.
Check for an existing solution
Before adding a new generic primitive, consider shadcn/ui. If you port a pattern, align it with this repo’s tokens and APIs.
Tailwind and design tokens
- Tokens live in
apps/presentation/app/globals.cssinside@theme { }(colors, typography, z-index, shadows, etc.). Prefer utilities that map to those tokens over unrelated hardcoded values. - Tailwind utilities are the default styling approach.
TypeScript
- Props — Fully typed; avoid
any; use unions where they clarify allowed values. - Variants — Use
cva(class-variance-authority) andVariantPropswhen a component has multiple visual or behavioural variants. "use client"— Prefer server-friendly components; add"use client"only when you need client-only APIs (hooks, browser APIs).
Storybook
For components under components/ui/, add a story under apps/storybook/src/stories/ui/<component>.stories.tsx (or a subfolder). Expose controls for the main props so the component can be exercised in isolation.
Tests
- Shared UI —
apps/presentation/components/ui/__tests__/<component>.test.tsx, or__tests__/next to the component when it lives in a subfolder (e.g.components/ui/carousel/__tests__/). - Feature UI — Colocate tests with the feature.
Imports and naming
- Alias — Use
@/from the presentation app root (e.g.@/components/ui/button,@/features/cart/cart-content). - Files — kebab-case (
product-card.tsx). - Exports — PascalCase named exports for React components.
- Features — Outside a feature, import only from that feature’s public root; ESLint enforces this.
Related
- Feature — Feature folders and import boundaries
- Icons
- Translations
- Maintain contracts
- General workflow rules