Core Framework Design Token System and CSS Generation in Instatic: A Complete Technical Guide
Instatic implements a strict design-token architecture using CSS custom properties declared in src/styles/globals.css and consumed via CSS Modules, eliminating hard-coded values through automated architectural testing.
The Core Framework design token system and CSS generation in Instatic establishes a single source of truth for visual styling across the admin interface, shared UI primitives, and published sites. Unlike Tailwind-driven or CSS-in-JS approaches, Instatic relies on pure CSS custom properties processed through Vite's build pipeline to deliver theme-ready, performant styling with zero runtime overhead.
How the Design Token System Works in Instatic
Instatic's token architecture follows a strict semantic hierarchy defined in a centralized stylesheet and enforced through CI-level testing.
Token Definition in globals.css
All design tokens originate in src/styles/globals.css inside the :root selector, making them globally available to every component. This file defines the complete visual vocabulary including colors, spacing, and radii.
/* src/styles/globals.css */
:root {
/* Surface tokens */
--editor-surface: #ffffff;
--editor-surface-2: #f5f5f5;
/* State tokens */
--editor-danger: #ef4444;
--editor-success-bg: #dcfce7;
/* Identity tokens */
--rail-tint-mint: #10b981;
--rail-tint-sky: #0ea5e9;
/* Geometry tokens */
--editor-radius: 6px;
}
The Vite build pipeline processes this file during bun run build, injecting these variables into the global scope without additional JavaScript processing.
Semantic Naming Conventions
Instatic enforces a strict semantic naming scheme documented in docs/design.md. Tokens are categorized into three distinct types:
- State tokens represent functional UI states (e.g.,
--editor-danger,--editor-success-bg) - Identity tokens define brand and accent colors (e.g.,
--rail-tint-mint,--rail-tint-sky) - Surface tokens control backgrounds and elevations (e.g.,
--editor-surface,--editor-surface-2)
Hard-coded hex or RGB values are explicitly prohibited outside of the :root declaration. Every visual value must reference a token, ensuring that changing a single variable cascades through the entire interface instantly.
Vite-Powered CSS Generation Pipeline
The CSS generation relies on Vite's native CSS processing rather than Tailwind utilities or CSS-in-JS libraries. The build configuration in vite.config.ts bundles globals.css and all CSS Module files into the production output.
When you run bun run build, Vite processes the following:
- Extracts and bundles global CSS variables from
src/styles/globals.css - Processes component-level CSS Modules (e.g.,
Button.module.css) - Resolves
var(--token-name)references at the browser level - Outputs optimized CSS with zero runtime JavaScript overhead for styling
This approach keeps bundle sizes minimal and leverages browser-native variable resolution during the layout stage.
Consuming Tokens in Components
Components reference tokens through CSS Modules, maintaining strict isolation while tapping into the global design system.
CSS Modules Integration
UI components import scoped styles that reference global tokens via the var() function. For example, a widget component in src/ui/components/Widget/Widget.module.css consumes surface and geometry tokens:
/* src/ui/components/Widget/Widget.module.css */
.widget {
background: var(--editor-surface-2);
border-radius: var(--editor-radius);
border: 1px solid var(--rail-tint-sky);
padding: var(--editor-spacing-md);
}
Because Instatic enables the React Compiler, these component style references are automatically memoized without requiring manual useMemo hooks. The CSS Module approach eliminates naming collisions while maintaining access to the global token system.
Runtime Overrides and Theming
The token system supports dynamic theming through runtime overrides without rebuilding the application. The workspace layout store in src/admin/state/workspaceLayout.ts can inject custom token values via inline styles on root elements.
To override tokens at runtime:
// src/admin/state/workspaceLayout.ts
<div style={{ '--editor-radius': '8px' }}>
{/* Child components inherit the new radius value */}
</div>
This capability enables instant theme switching, dark mode toggles, and brand-specific customizations by modifying CSS custom properties in the DOM rather than regenerating stylesheets.
Enforcing Design Discipline with Automated Testing
Instatic prevents visual regression through architectural tests that enforce token usage. Two critical test files guard against anti-patterns:
src/__tests__/architecture/css-token-policy.test.ts validates that no hard-coded color literals exist in component styles. Any hex code, RGB, or HSL value outside of globals.css causes CI failure.
src/__tests__/architecture/no-css-var-fallbacks.test.ts ensures developers do not include fallback values in var() declarations (e.g., var(--token, #000)), maintaining strict dependency on the centralized token system.
These tests run automatically in CI, preventing "leaky" styles and ensuring that the Core Framework design token system and CSS generation strategy remains consistent across all contributions.
Summary
- Design tokens are CSS custom properties defined in
src/styles/globals.cssinside the:rootselector, serving as the single source of truth for colors, spacing, and radii. - Vite bundles tokens globally during
bun run build, making variables available to all CSS Modules without JavaScript processing overhead. - Components consume tokens via CSS Modules using
var(--token-name)syntax, with automatic memoization provided by the React Compiler. - Runtime theming is supported by overriding tokens through the
styleattribute, implemented insrc/admin/state/workspaceLayout.ts. - Automated architecture tests in
css-token-policy.test.tsandno-css-var-fallbacks.test.tsenforce the ban on hard-coded values and fallback declarations.
Frequently Asked Questions
Why does Instatic use CSS variables instead of Tailwind or CSS-in-JS?
According to the CoreBunch/Instatic source code, CSS custom properties provide native browser performance with zero runtime overhead, unlike CSS-in-JS libraries that inject styles via JavaScript. The approach eliminates the need for utility-class bloat while enabling runtime theming capabilities that static utility frameworks cannot support. Variables are resolved during the browser's layout stage, keeping bundle sizes minimal and render times fast.
How does the build process handle CSS token generation?
The Vite configuration in vite.config.ts processes src/styles/globals.css during the bun run build command, injecting the :root variables into the global stylesheet. Because tokens are pure CSS, they require no preprocessing or runtime generation—Vite bundles them as static assets, and the browser handles variable resolution automatically. This eliminates the need for build-time token transformation pipelines.
Can design tokens be customized without rebuilding the application?
Yes, Instatic supports runtime token overrides through the workspace layout state in src/admin/state/workspaceLayout.ts. Developers can modify token values via inline styles (e.g., style={{ '--editor-radius': '8px' }}) on container elements, and child components inherit these new values immediately. This enables dynamic theming, dark mode switching, and brand customization without recompiling the bundle.
How does Instatic prevent developers from using hard-coded colors?
The repository includes architectural tests in src/__tests__/architecture/css-token-policy.test.ts that scan the codebase for prohibited hex codes, RGB, and HSL values. Additionally, no-css-var-fallbacks.test.ts prevents fallback values in var() declarations. These tests run in CI and fail the build if they detect violations, ensuring strict adherence to the token-based design system.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →