Skip to content

ADR 006 Styling Approach

Claude product-architect (Opus 4.6) edited this page Feb 22, 2026 · 3 revisions

ADR-006: Styling Approach

Status

Accepted (Revised -- originally Tailwind CSS v4, changed to CSS Modules)

Context

Cornerstone needs a CSS approach that supports:

  • Responsive design (desktop, tablet, mobile-friendly)
  • Consistent design system (colors, spacing, typography)
  • Interactive components (Gantt chart, drag-and-drop, modals, forms)
  • Touch-friendly interfaces for mobile/tablet
  • Fast development iteration
  • Small production bundle size

Constraint: No Native Binary Dependencies for Frontend Tooling

Per ADR-004, the frontend build chain must avoid native binary dependencies. This eliminates tools that rely on native code for CSS processing.

Alternatives Considered

Tailwind CSS v4 (original decision)

  • Utility-first CSS framework with zero runtime
  • Excellent responsive design utilities
  • Design system built in
  • v4 uses an oxide engine that ships native binaries
  • Rejected: Tailwind CSS v4's oxide engine depends on Lightning CSS, which ships platform-specific native binaries that crash on ARM64 emulation. This is the same class of issue that eliminated Vite (ADR-004).

styled-components / Emotion (CSS-in-JS)

  • Dynamic styles based on props
  • Runtime CSS injection -- adds JavaScript overhead
  • Larger bundle size due to runtime
  • Good component encapsulation but slower development for layout work
  • Not chosen: Runtime overhead and bundle size penalty are unnecessary for this project's scale.

CSS Modules

  • Scoped CSS per component; no class name collisions
  • Standard CSS syntax with module import (import styles from './Foo.module.css')
  • Works with Webpack's css-loader (pure JavaScript, no native binaries)
  • No runtime overhead -- compiled to unique class names at build time
  • CSS custom properties (variables) provide a lightweight design system
  • Full control over responsive design via standard media queries
  • Well-supported in the React ecosystem

Decision

Use CSS Modules for component-scoped styling, processed by Webpack's css-loader.

How It Works

Each component has a co-located .module.css file:

components/
  Sidebar/
    Sidebar.tsx
    Sidebar.module.css

CSS classes are imported as a typed object:

import styles from './Sidebar.module.css';

function Sidebar() {
  return <nav className={styles.sidebar}>...</nav>;
}

Webpack's css-loader transforms class names to unique identifiers (e.g., Sidebar_sidebar_a1b2c) at build time, preventing collisions.

Design System

CSS custom properties (variables) defined in a global stylesheet (client/src/styles/index.css) provide the design system:

:root {
  --color-primary: #2563eb;
  --color-surface: #ffffff;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  /* etc. */
}

Components reference these variables, ensuring visual consistency without a framework dependency.

Responsive Design

Standard CSS media queries within each module handle responsive layouts:

.sidebar {
  width: 280px;
}

@media (max-width: 768px) {
  .sidebar {
    transform: translateX(-100%);
  }
}

TypeScript Support

A type declaration file (client/src/types/css.d.ts) provides typing for CSS Module imports:

declare module '*.module.css' {
  const classes: { readonly [key: string]: string };
  export default classes;
}

Test Support

In Jest tests, identity-obj-proxy mocks CSS Module imports, returning class names as strings (e.g., styles.sidebar returns "sidebar").

Consequences

Positive

  • Pure JavaScript build chain -- no native binary dependencies
  • Zero runtime overhead (styles are compiled at build time)
  • Component-scoped styles prevent class name collisions
  • Standard CSS syntax -- no framework-specific learning curve
  • Full control over responsive design, animations, and custom components (e.g., Gantt chart)
  • CSS custom properties provide a lightweight, standards-based design system
  • Works seamlessly with Webpack (ADR-004) and Jest (ADR-005)

Negative

  • No built-in utility classes -- requires writing more CSS for common patterns (padding, margin, flex)
  • Responsive styles require explicit media queries in each module (no shorthand prefixes like Tailwind's md:)
  • No design system out of the box -- must define and maintain custom properties manually
  • More CSS files to maintain compared to utility-first approaches

Clone this wiki locally