@varialkit/styles
v0.1.3
Published
This package contains the core visual foundations of the design system, including themes, tokens, and typography. It provides a centralized system for managing the look and feel of the application.
Readme
Styles Package
This package contains the core visual foundations of the design system, including themes, tokens, and typography. It provides a centralized system for managing the look and feel of the application.
Architectural Philosophy
The styling architecture is designed to be modular, scalable, and maintainable. The key principles are:
- Separation of Concerns: The system separates raw color values (primitives) from their semantic meaning (tokens). This allows for a clear distinction between the available color palette and its application in the UI.
- Theming with CSS Variables: The use of CSS variables for theming allows for dynamic theme switching without requiring a full re-render of the application. This is both efficient and flexible.
- Single Source of Truth: Token data is stored in TypeScript files (e.g.,
color-data.ts), which serve as a single source of truth for both the SCSS variables and the documentation site. This ensures consistency and reduces the risk of outdated documentation.
Package Structure
The styles package is organized into the following directories:
colors/: Contains the raw color primitives used throughout the design system.themes/: Defines the light and dark themes using semantic color tokens.tokens/: Contains the design tokens for density, spacing, radius, elevation, and color.typography/: Includes the base typography styles.
Radius tokens include --radius-0 for sharp corners when no rounding is desired.
Ecosystem Integration
The styles package is a foundational part of the monorepo and is consumed by other packages, most notably the website application.
Website Integration
The website application imports the compiled styles directly into its root layout, ensuring that all design tokens and theme variables are available globally. This is done in apps/website/app/layout.tsx:
import "@solara/styles/index.scss";This single import provides the entire application with the core styling foundations, allowing components to use the design tokens and themes consistently.
Token Documentation
A key feature of this system is the automated generation of token documentation. The tokens directory contains data files (e.g., color-data.ts, spacing-data.ts) that export arrays of token metadata.
These data files serve as a single source of truth for the design tokens. The documentation website dynamically imports this data to generate the token reference pages. For example, the color documentation page at apps/website/app/styles/[...slug]/page.tsx imports colorPalettes and colorTokens from packages/styles/tokens/color-data.ts and renders them as interactive documentation.
This approach ensures that the documentation is always in sync with the actual design tokens, as they are both derived from the same source.
Global Density
Density is controlled globally via a data-density attribute on the root <html> element. Tokens expose separate CSS custom properties for spacing, typography, icon sizing, and radius so each axis can be tuned independently.
<html data-density="density-2">
...
</html>Available density values
density-1density-2(default)density-3density-4
How it works
- The active density sets the base multipliers on the root.
- Components should not expose a
densityprop. Prefer semanticsizeprops (small|medium|large) and multiply internal spacing using the spacing multiplier.
padding: calc(var(--space-3) * var(--spacing-multiplier));
font-size: var(--font-size-body-scaled);Website implementation
- The docs site sets
data-densityon<html>inapps/website/app/components/ThemeProvider.tsx. - The density tokens live in
packages/styles/tokens/density.scssand are included bypackages/styles/index.scss.
Overrides
- Optional overrides are supported via
--spacing-multiplier-override,--font-size-multiplier-override,--icon-size-multiplier-override, and--radius-multiplier-override. When unset, the base density values apply.
Typography Tokens
The typography base defines a semantic scale (h1–h5, subhead, body, caption, footnote) plus line-height tokens. Components should reference these tokens rather than hard-coded sizes so font-size multiplier changes scale reliably.
Font families
--font-sans: default sans serif stack--font-serif: default serif stack--font-mono: default mono stack--font-body: body copy alias (defaults to--font-sans)--font-heading: heading alias (defaults to--font-sans)
Customization
Override the font variables once (for example on :root or <html>) to swap families across the system without touching component styles.
:root {
--font-sans: "Inter", "Segoe UI", system-ui, sans-serif;
--font-serif: "Literata", "Georgia", serif;
--font-body: var(--font-sans);
--font-heading: var(--font-serif);
}Body-like semantic controls
subhead, body, caption, and footnote now expose dedicated weight and underline tokens so components can opt in to consistent text emphasis:
--font-weight-subhead,--font-weight-subhead-bold--font-weight-body,--font-weight-body-bold--font-weight-caption,--font-weight-caption-bold--font-weight-footnote,--font-weight-footnote-bold--text-decoration-subhead,--text-decoration-subhead-underline--text-decoration-body,--text-decoration-body-underline--text-decoration-caption,--text-decoration-caption-underline--text-decoration-footnote,--text-decoration-footnote-underline
Contributing
Contributions to the styling system are welcome. Here’s how to add new tokens and test your changes.
Adding New Color Tokens
To add a new color token, you need to update the following files:
packages/styles/colors/_primitives.scss: If you are introducing a new color, add it to the appropriate color scale.packages/styles/themes/light.scss: Add the new semantic token and assign it a color from the primitives.packages/styles/themes/dark.scss: Add the same token and assign it a color suitable for the dark theme.packages/styles/tokens/color-data.ts: Add the new token to thecolorTokensarray. This will automatically update the documentation website.
Local Development
To test your changes locally, you can run the website application, which serves as a live playground for the design system.
- Navigate to the root of the monorepo.
- Run
pnpm devto start the development server. - Open your browser to
http://localhost:3000to see your changes in real-time.
Usage
To use the styles package, import the index.scss file into your main application stylesheet:
@import "@solara/styles/index.scss";Recommended Theme Integration For App Consumers
If you are consuming Solara from npm in your own app, the recommended pattern is to create a single app-level runtime owner for theme state.
That runtime owner should:
- initialize with
getDefaultThemeConfig() - normalize updates with
mergeThemeConfig() - apply the final config to
document.documentElementwithapplyThemeConfig() - persist any user-configurable settings in your app storage layer
- derive app-specific assets or UI behavior from the same theme state when needed
Example:
import { useEffect, useState } from "react";
import {
getDefaultThemeConfig,
mergeThemeConfig,
type SolaraThemeConfig
} from "@solara/styles/config";
import { applyThemeConfig } from "@solara/styles/runtime";
export function AppThemeRuntime() {
const [config, setConfig] = useState<SolaraThemeConfig>(getDefaultThemeConfig());
useEffect(() => {
applyThemeConfig(document.documentElement, config);
}, [config]);
const updateTheme = (themeId: SolaraThemeConfig["themeId"]) => {
setConfig((prev) => mergeThemeConfig({ ...prev, themeId }));
};
return null;
}Ownership Boundary
@solara/stylesshould own typed design-system config, runtime attributes, and CSS variables- your application should own storage, theme controls, logo/asset swaps, and product-specific shell behavior
In other words, Solara owns the design-system runtime contract, and your app owns anything derived from that contract that is specific to your product.
Examples of app-owned theme logic:
- light/dark logo selection
- illustration or marketing asset swaps
- app background presets
- product-specific navigation or shell chrome changes
Keeping this split clean makes it easier for consumers to upgrade @solara/styles without overloading the shared config shape with app-only concerns.
In production apps, prefer applying the theme through applyThemeConfig() so all supported root attributes and CSS variables stay in sync. Under the hood, Solara applies root attributes such as data-theme, data-theme-id, and data-density on the <html> element.
The underlying root contract looks like this:
<html data-theme="light">
...
</html>