# How CSS Classes Are Scoped and Managed in the Instatic Editor

> Discover how Instatic scopes CSS classes using Vite hashing and a global token system. Learn about component isolation and CSS Modules for efficient styling.

- Repository: [CoreBunch/Instatic](https://github.com/CoreBunch/Instatic)
- Tags: internals
- Published: 2026-08-01

---

**Instatic scopes CSS classes using a strict CSS Modules-only architecture where Vite hashes class names at build time to guarantee component isolation, while a centralized token system in [`src/styles/globals.css`](https://github.com/CoreBunch/Instatic/blob/main/src/styles/globals.css) manages all visual values and is enforced by automated tests.**

The Instatic editor, developed by CoreBunch using React 19, implements a rigorous styling system designed to eliminate global CSS pollution and prevent naming collisions. By mandating CSS Modules for all component-specific styles and prohibiting Tailwind utilities, the codebase ensures that CSS classes are scoped locally and managed through a design-token-driven approach.

## Local Scoping via CSS Modules

Instatic enforces a CSS Modules-only policy as documented in [`docs/design.md`](https://github.com/CoreBunch/Instatic/blob/main/docs/design.md) and [`docs/editor.md`](https://github.com/CoreBunch/Instatic/blob/main/docs/editor.md). Every React component that requires custom styling must maintain a co-located [`Component.module.css`](https://github.com/CoreBunch/Instatic/blob/main/Component.module.css) file within the same directory as its TypeScript implementation.

### Component-Level Module Files

When a developer imports a CSS Module using `import styles from "./Component.module.css"`, the build pipeline processes the file to generate unique class names. For instance, a class defined as `.button` in [`src/ui/components/Button/Button.module.css`](https://github.com/CoreBunch/Instatic/blob/main/src/ui/components/Button/Button.module.css) is transformed at build time into a hashed identifier such as `Button_button__xYz12`, ensuring it is scoped exclusively to that component instance and cannot leak into the global namespace.

```tsx
// src/ui/components/Button/Button.tsx
import { cn } from '@ui/cn'               // tiny class‑name combiner
import styles from './Button.module.css' // CSS‑Modules import

type Props = {
  /** optional extra classes */
  className?: string
  /** button label */
  children: React.ReactNode
}

/** Simple button that follows the Instatic styling rules */
export const Button = ({ className, children }: Props) => (
  <button className={cn(styles.button, className)}>
    {children}
  </button>
)

```

```css
/* src/ui/components/Button/Button.module.css */
.button {
  /* token‑based styling – never a hard‑coded color */
  background: var(--accent-2);
  color: var(--text-bright);
  border-radius: var(--editor-radius);
  padding: var(--space-xs) var(--space-m);
  font-size: var(--text-s);
}

```

### Vite Build Integration

The project uses Vite with Bun as its build tooling. Vite's native CSS Modules configuration automatically handles the generation of hashed class names and injects the resulting styles at runtime. Because the React Compiler auto-memoizes components, the imported `styles` object remains referentially stable across renders, eliminating the need for manual `useMemo` or `useCallback` hooks for style references.

## Managing Visual Values with Design Tokens

All visual values—colors, spacing, typography, and radii—are defined as CSS custom properties in [`src/styles/globals.css`](https://github.com/CoreBunch/Instatic/blob/main/src/styles/globals.css). This file serves as the single source of truth for the entire application's visual design, ensuring consistent styling across `src/ui/` and `src/admin/` components.

### Token-Based Styling

CSS modules must reference these tokens using `var(--token-name)` syntax rather than hard-coded hex codes, pixel values, or rem units. The [`globals.css`](https://github.com/CoreBunch/Instatic/blob/main/globals.css) file defines variables such as `--text-s`, `--space-xs`, `--accent-2`, and `--editor-radius`, which components consume to maintain visual consistency.

### Automated Enforcement

Compliance with the token system is verified by the test suite in [`src/__tests__/architecture/css-token-policy.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/__tests__/architecture/css-token-policy.test.ts). This test ensures that no CSS module contains literal color values or arbitrary units, forcing all styling decisions through the centralized token catalog documented in [`docs/reference/design-tokens.md`](https://github.com/CoreBunch/Instatic/blob/main/docs/reference/design-tokens.md).

## Class Name Composition

To safely combine locally scoped classes with external props, Instatic provides a lightweight utility in [`src/ui/cn.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/ui/cn.ts). This helper merges the CSS Module object with any `className` passed via props, allowing components to remain extensible while preserving their base styles.

## Prohibited Patterns

The repository strictly bans Tailwind utilities and raw CSS imports outside of the designated folders. The only permitted global stylesheet is [`src/styles/globals.css`](https://github.com/CoreBunch/Instatic/blob/main/src/styles/globals.css); all other styles must reside in CSS modules under `src/admin/`, `src/admin/pages/site/`, or `src/ui/`. These constraints are validated by [`noTailwindUtilities.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/noTailwindUtilities.test.ts) and the CSS token policy tests.

## Summary

- **CSS Modules-only**: Every component uses co-located `*.module.css` files to ensure styles are scoped via build-time hashing.
- **Automatic scoping**: Vite generates unique hashed class names (e.g., `Button_button__xYz12`) that prevent collision with other components.
- **Design tokens**: All visual values are defined in [`src/styles/globals.css`](https://github.com/CoreBunch/Instatic/blob/main/src/styles/globals.css) and referenced via CSS variables, enforced by [`css-token-policy.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/css-token-policy.test.ts).
- **Composition utility**: The `cn` helper in [`src/ui/cn.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/ui/cn.ts) safely merges local styles with external `className` props.
- **Strict prohibitions**: Tailwind and arbitrary global CSS are banned, with compliance verified by the test suite.

## Frequently Asked Questions

### How does Instatic prevent CSS class name collisions?

Instatic relies on CSS Modules processed by Vite. When a component imports its associated [`.module.css`](https://github.com/CoreBunch/Instatic/blob/main/.module.css) file, the build system rewrites each class name to a unique hash derived from the component path and original class name. This guarantees that `.button` in one component becomes `Button_button__xYz12` while `.button` in another becomes something like `Card_button__aBc34`, eliminating any risk of global namespace pollution.

### Why doesn't Instatic use Tailwind CSS?

The project explicitly bans Tailwind utilities as documented in [`docs/design.md`](https://github.com/CoreBunch/Instatic/blob/main/docs/design.md) and enforced by [`noTailwindUtilities.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/noTailwindUtilities.test.ts). The maintainers opted for CSS Modules to ensure strict component isolation and to force all visual decisions through the centralized design token system in [`globals.css`](https://github.com/CoreBunch/Instatic/blob/main/globals.css), preventing utility class proliferation and maintaining a single source of truth for spacing, color, and typography values.

### How are design tokens enforced in CSS modules?

The test file [`src/__tests__/architecture/css-token-policy.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/__tests__/architecture/css-token-policy.test.ts) scans all CSS modules for hard-coded values such as hex colors, pixel units, or rem values. If a module contains any literal values instead of `var(--token-name)` references, the test suite fails, ensuring that every visual property derives from the tokens defined in [`src/styles/globals.css`](https://github.com/CoreBunch/Instatic/blob/main/src/styles/globals.css).

### What build tools handle the CSS module hashing?

Instatic uses Vite paired with Bun as its build pipeline. Vite's built-in CSS Modules configuration automatically handles the compilation, hashing, and injection of scoped class names without additional configuration. The React Compiler further optimizes runtime performance by ensuring the imported styles object remains referentially stable across component renders.