Skip to content
RoamDesign System

Philosophy

Design Philosophy

The principles that guide every design and engineering decision at Roam.

Clean, open, modern

White space is a primary design tool — not empty space to fill. Brand colours are vibrant and used with intention as accents, not as fills for large surfaces.

Mobile first

The majority of traffic comes from mobile devices. Start with the small-screen layout and progressively enhance using Tailwind responsive prefixes (md:, lg:, xl:).

Move fast without sacrificing quality

shadcn/ui and Tailwind are the foundation. We build on top of them, not around them. Team members should ship UI confidently using existing primitives.

Neutral-first interface

Black and white for interactive elements, brand colours for accents only. A neutral palette creates the clearest action hierarchy and avoids colour conflicts.

Stack

Tech Stack

The technologies that power curbo-web. Know the stack before you ship.

LayerTechnology
FrameworkNext.js 15 (pages/ router)
LanguageJavaScript / TypeScript (mixed)
StylingTailwind CSS v3
Component libraryshadcn/ui (primary default)
PrimitivesRadix UI (via shadcn)
Legacy UIMUI v5 — existing only, do not use for new work
CMSBuilder.io
StateRecoil
FormsFormik
Data fetchingSWR + Axios
AuthNextAuth.js
TestingJest + RTL (unit), Playwright (e2e)
DeploymentNetlify

Components

Component Approach

How we choose, build, and organise components. shadcn/ui is the default — custom components are the exception.

Decision Flow

1. Use shadcn/ui

Always check if shadcn has a component that fits. Use it even if it needs minor Tailwind overrides.

2. Extend shadcn

If the shadcn component is close but needs composition (e.g. wrapping in a card, adding a label), extend it — don’t rebuild.

3. Build custom

Only when no shadcn component covers the use case, or the modification would make it unrecognisable. Must still use Tailwind and follow shadcn conventions.

Directory Structure

components/
├── ui/                  # shadcn/ui — do not modify unless necessary
├── Common/              # Shared utility components
├── Layouts/             # Page layout wrappers
├── Navbar/              # Site navigation
├── Footer/              # Site footer
├── CarCards/            # Vehicle listing cards
├── Checkout/            # Checkout flow components
├── Dashboard/           # Customer dashboard
├── Filters/             # Browse/filter UI
├── FormInput/           # Form field components
└── ...                  # Other feature-specific components

The ui/ directory is managed by shadcn — avoid editing these files directly. Domain-specific components live in their own directories (CarCards, Checkout, etc.).

Styling

Styling Rules

The order of preference for styling and the hard rules that apply to all code.

Order of Preference

#MethodWhen to Use
1shadcn/ui componentAlways check here first
2Tailwind utility classesLayout, spacing, style overrides on shadcn components
3CSS ModulesOnly when Tailwind cannot express the style
4Global CSS (globals.css)Base resets and third-party library overrides only

Hard Rules

No inline styles

Never use style={{}} props. All styles go through Tailwind or CSS Modules.

No raw hex values in JSX

Always use Tailwind tokens or CSS variables. Never write color: #F93771 in component code.

No new component libraries

Do not install a new component library without discussion. Use shadcn/ui first.

No new MUI components

MUI/Material UI is legacy. All new work uses shadcn + Tailwind. Existing MUI components may remain until migrated.

Correct Pattern

// Good — Tailwind tokens only
<Button className="bg-primary text-primary-foreground">
  Subscribe
</Button>

// Bad — inline style with raw hex
<button style={{ backgroundColor: '#0A0A0A', color: '#fff' }}>
  Subscribe
</button>

// Bad — new library import
import { Button } from '@chakra-ui/react';

Colour

Colour in UI

How colour is applied in the interface. The UI is neutral-first — brand colours are accents, not foundations.

Primary CTA: Black

Use black (zinc-950 / #0A0A0A) as the primary CTA background. A neutral black CTA creates the clearest action hierarchy, works on any background, and avoids colour conflicts with brand accents or destructive states.

Fuchsia: Accent Only

Allowed

  • Icon tints and decorative icon colour
  • Small UI accents (underlines, indicators)
  • Labels, badges, and promotional pills
  • Brand moments within components

Never

  • Buttons (any variant) — too close to destructive red
  • Links — must use neutral colours
  • Large component fills — overwhelming

Links

Links use neutral colours, not brand colours. They should feel part of the typographic system, not compete with accents.

Inline text links

text-foreground underline or text-muted-foreground underline

Navigation links

text-foreground or text-muted-foreground, no underline (hover underline OK)

Functional / Utility Colours

For non-brand UI states, use Tailwind’s built-in palette:

StateTailwind Colours
Destructive / errorred-500, red-600, red-700
Successgreen-500, green-600
Warningamber-400, amber-500
Infoblue-500, blue-600
Muted textslate-500, muted-foreground
Neutral labelsslate-100–300 (light), slate-700–800 (dark)

Theming

Dark Mode

Dark mode is supported and must be considered for all new components.

How It Works

CSS variable system

All shadcn component colours reference CSS variables (--background, --foreground, --primary, --muted, etc.).

Class-based toggle

The dark class on <html> switches modes.

Guidelines

  • Do not hardcode light-mode colours. Always use shadcn tokens or Tailwind’s dark: variant.
  • Light mode: White/near-white backgrounds, dark blue and fuchsia accents.
  • Dark mode: Deep dark backgrounds (near #13013F), fuchsia and lighter purple as accents, white/light text.
  • Test both modes before shipping every new component.
  • shadcn components handle dark mode automatically when CSS variables are set correctly.

Pattern

// Good — uses shadcn token, adapts automatically
<div className="bg-background text-foreground">

// Good — explicit dark variant
<div className="bg-white dark:bg-zinc-900">

// Bad — hardcoded light colour, breaks in dark mode
<div className="bg-white text-black">

Iconography

Icons

Consistent iconography across the site. One source, one style.

Sources

Primary: shadcn/ui defaults

Use icons bundled with shadcn/ui. These are always the first choice.

Extended: shadcn Icons Library

When the default set doesn’t have what you need, check shadcn.io/icons.

Rules

  • Consistency is mandatory — do not mix icon styles (line vs filled) or icons from incompatible libraries.
  • Size with Tailwind: w-4 h-4 (16px), w-5 h-5 (20px), w-6 h-6 (24px).
  • Use currentColor so icons inherit text colour and adapt to dark mode automatically.
  • Brand accent icons can use fuchsia or dark blue explicitly where appropriate.
  • Do not use Heroicons or Lucide directly for new work unless the icon truly doesn’t exist in the shadcn set.

Sizing Reference

ClassSizeUse Case
w-4 h-416pxInline with text, buttons, form fields
w-5 h-520pxNavigation items, list icons
w-6 h-624pxStandalone icons, feature highlights