Skip to main content
Every component in this project scopes its styles with CSS Modules. Style files are co-located with the component and named index.module.css.

File naming

Follow the component’s directory structure:
MyComponent/
├── index.tsx
└── index.module.css   ← styles live here

Importing in TSX

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

const MyComponent = () => (
  <div className={styles.container}>
    <h2 className={styles.title}>Hello</h2>
  </div>
);
CSS Modules automatically generates unique class names at build time, so .container in one component never collides with .container in another.

Writing styles

Use the @apply directive to compose Tailwind utilities inside CSS Modules:
/* index.module.css */
.container {
  @apply flex
    flex-col
    gap-4
    rounded-lg
    bg-white
    p-6
    shadow-sm;
}

.title {
  @apply text-xl
    font-semibold
    text-gray-900;
}

.description {
  @apply leading-relaxed
    text-gray-600;
}

Style guidelines

CSS Modules are accessed as JavaScript property lookups. Use camelCase so you can write styles.myClassName without bracket notation.
/* ✅ camelCase */
.cardTitle { ... }
.isActive { ... }

/* ❌ kebab-case requires bracket notation */
.card-title { ... }
List each @apply utility on its own line. This makes diffs easier to read and utilities easier to reorder.
/* ✅ one per line */
.button {
  @apply px-4
    py-2
    rounded
    font-medium;
}

/* ❌ all on one line */
.button {
  @apply px-4 py-2 rounded font-medium;
}
When a Tailwind utility covers what you need, use @apply rather than writing plain CSS. This keeps the design system consistent.
/* ✅ Tailwind utility */
.link {
  @apply text-green-600
    underline;
}

/* ❌ plain CSS for things Tailwind covers */
.link {
  color: #16a34a;
  text-decoration: underline;
}
Never write styles that target elements outside the component’s root. Avoid global selectors inside module files.

Combining class names

When a component needs conditional or variant classes, combine them with template literals or the classnames package (available as classnames in the monorepo):
import cn from 'classnames';
import styles from './index.module.css';

const Card: FC<CardProps> = ({ variant = 'default' }) => (
  <div className={cn(styles.card, styles[variant])}>
    ...
  </div>
);
Or with template literals for simpler cases:
<div className={`${styles.card} ${styles[variant]}`}>

Linting

CSS files are linted with Stylelint. Run the linter from the package root:
pnpm lint:css

# Auto-fix where possible
pnpm lint:css:fix
The project uses stylelint-config-standard, stylelint-order, and stylelint-selector-bem-pattern.

Tailwind CSS

How Tailwind v4 is configured and how @apply works.

Responsive design

Responsive breakpoints and mobile-first patterns.

Build docs developers (and LLMs) love