Frontend Design System - Yosemite Crew
Description
Use this skill when working on UI in apps/frontend. It teaches you how to use our custom design system, component library, and style conventions so you produce consistent, on-brand UI without reinventing the wheel.
TRIGGER: any task involving JSX, styling, layout, new components, or visual changes in apps/frontend.
Core Rule: Reuse Before Creating
Before writing any new UI element, search the existing component library.
src/app/ui/ ← start here
Button.tsx ← variants: primary | secondary | danger
Card.tsx ← variants: default | bordered | subtle
Badge.tsx ← non-status labels (status chips use StatusPill)
Input.tsx ← base input with token borders
Stack.tsx ← flex layout helper
Text.tsx ← typography variants
inputs/ ← Datepicker, Dropdowns, Search, FileInput
cards/ ← Appointment, Inventory, Forms, etc.
tables/ ← DataTable variants
overlays/ ← Modal, Toast, Loader
layout/ ← Header, Sidebar, guards
primitives/Buttons/ ← Primary, Secondary, Delete (low-level)
primitives/StatusPill/ ← THE status pill (tone-coloured, uppercase)
primitives/SegmentedPill/ ← segmented pill controls (view/tab toggles)
filters/ ← Forms, Inventory, general filters
board/ ← kanban board components
widgets/ ← domain widgets
Import from the barrel: import { Button, Card, Badge } from '@/app/ui'
Design Tokens
The design-token source of truth is apps/frontend/src/app/globals.css - the Tailwind @theme block PLUS the runtime layers below it: :root (the warm-bone light palette: --blue, --ink, --screen, --band, --hairline, ...) and html[data-theme="dark"]. The short-form tokens outnumber --color-* in app code roughly 3:1, so "use --color-*" is not the rule - match the token layer the surrounding code uses (apps/frontend/AGENTS.md has the full token-layer map). Never hardcode hex values or px sizes - always use tokens.
/* Colors */
--color-* (Tailwind @theme, e.g. --color-neutral-200)
--blue, --ink, --screen, --band, --hairline (warm-bone runtime layer: :root + html[data-theme="dark"])
/* Typography */
--font-satoshi (body/UI - all weights 300-900)
--font-newsreader (display serif - page titles, marketing moments)
Satoshi is the body/UI font; Newsreader (--font-newsreader, applied via .text-page-title / .font-newsreader) is the display serif for page titles and marketing moments. The durable rule: never re-add --font-grotesk or --grotesk-font (see src/app/ui/tokens.md).
Reference documentation: src/app/ui/tokens.md (derived guide, not source of truth)
Styling Rules
- Tailwind CSS 4 is the styling system. Use utility classes.
- Use
clsxfor conditional class composition - it's already in the project. - Never write inline
style={{}}unless a value cannot be expressed as a token. - Never add raw Bootstrap classes to new code - Bootstrap is legacy, do not spread it.
- Never use arbitrary Tailwind values (e.g.
w-[347px]) unless strictly required for pixel-perfect alignment from design specs.
Class ordering (Tailwind)
Layout → Spacing → Sizing → Typography → Colors → Borders → Effects → Responsive
Typography
Use the <Text> component for all copy, not bare <p> / <span> tags.
Body/UI font: Satoshi (300 Light → 900 Black). Display serif: Newsreader for page titles and marketing moments (.text-page-title in globals.css applies it). Never default to Inter, Roboto, or system fonts for new UI.
UI Text Normalization
- Never show raw backend enums, acronyms, or short forms in user-visible copy (for example
PAYMENT_AT_CLINIC,VET,PMS). - Always map domain values to plain-language labels before rendering.
- Do not use
Actoras a user-facing label. Use contextual labels such asLead/Support, or neutralUpdated bywhen role context is unknown.
Component Patterns
Creating a new component
- Search
src/app/ui/- if something similar exists, extend it. - If a new primitive is needed, place it in
src/app/ui/alongside its peers. - Domain-specific components go in the relevant
features/subdirectory. - Use TypeScript props with named types (no inline
{ prop: type }in function signatures).
Button usage
// Always use the wrapper, not primitives directly.
// Omit href for actions - href renders an <a> (Next.js Link); use it only for navigation.
<Button variant="primary" text="Save" />
<Button variant="secondary" text="Cancel" />
<Button variant="danger" text="Delete" />
State management
Use Zustand stores in src/app/stores/. Each domain has its own store. Do not introduce new state management libraries.
Available stores: appointment, appointmentWorkspace, auth, availability, companion, counter, document, forms, fullscreenLoader, integration, inventory, invoice, org, parent, profile, revampCatalog, room, routeLoader, search, service, signingOverlay, speciality, subscription, task, team, universalSearch. Lists drift — enumerate src/app/stores/ before creating any store.
Gotchas
- Do not nest
<button>inside<button>- invalid HTML, breaks tests. - Do not put icons in
<button>mocks in tests - use<span>not<button>for react-icons mocks. - Bootstrap classes are legacy; do not add new ones - Tailwind only for new code.
- Never use
--font-*values that don't exist in globals.css - check before using. - Never duplicate a store - check
src/app/stores/before creating new state. clsxnotcn,classnames, or template literals for conditional classes.- The design system does NOT use shadcn, Radix, or Material-UI - do not import them.
References
- Token source of truth: apps/frontend/src/app/globals.css
- Token map (reference): src/app/ui/tokens.md
- Component map: src/app/ui/README.md
- Detailed API signatures:
references/components-api.md