Web Applications
Complete guide to integrating Chassis design tokens into web applications using SCSS variables, CSS custom properties, and various bundler configurations.
This documentation was generated with AI assistance and has not been fully tested in production environments. While the content is based on standard platform practices and design token conventions, specific implementation details, code examples, or integration steps may require adjustments for your project setup.
If you encounter issues or inaccuracies, please report them via our issue tracker or refer to the official platform documentation for verification.
Overview
Chassis design tokens provide platform-agnostic design values that can be integrated into web applications in multiple ways. Tokens are transformed into SCSS variables with support for rem, px, and vw units, making them compatible with any modern web build pipeline.
Key Benefits:
- Consistency: Single source of truth for design values across all web projects
- Flexibility: Use SCSS variables directly or convert to CSS custom properties
- Responsive: Built-in support for multiple screen sizes and breakpoints
- Themeable: Light/dark mode support with automatic theme switching
- Type-safe: Generated with TypeScript definitions (optional)
This guide covers integration patterns for different project structures and popular bundlers including Webpack, Vite, Parcel, and Rollup.
Installation
Install the Chassis Tokens package from npm:
npm install @chassis-ui/tokens
Or using other package managers:
# pnpm
pnpm add @chassis-ui/tokens
# yarn
yarn add @chassis-ui/tokens
# bun
bun add @chassis-ui/tokens
The package includes pre-built token files for web platforms in the dist/web/ directory.
Package Structure
After installation, the tokens package contains the following structure:
node_modules/@chassis-ui/tokens/
└── dist/
└── web/
└── [app]/
└── [brand]/
├── main.scss # All non-theme, non-number tokens
├── string.scss # String tokens only
├── color-light.scss # Light mode color tokens
├── color-dark.scss # Dark mode color tokens
├── number-large.scss # Large screen tokens (if screens configured)
├── number-medium.scss # Medium screen tokens (if screens configured)
├── number-small.scss # Small screen tokens (if screens configured)
└── number.scss # All number tokens (if screens omitted)
File Types:
- main.scss: Base tokens (dimensions, typography, borders, shadows, etc.)
- string.scss: String tokens (SVG icons, asset URLs)
- color-[theme].scss: Theme-specific color tokens
- number-[screen].scss: Screen-size-specific numeric tokens (when screens are configured)
- number.scss: All numeric tokens in one file (when screens are not configured)
By default, the package includes chassis-docs tokens. You can build custom combinations using the token build process if you're working with the repository directly.
Basic Integration
Import All Tokens (SCSS)
The simplest approach is to import all tokens into your SCSS:
// Import base tokens
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
// Import theme tokens
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
// Import screen tokens
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-large";
// Now use tokens in your styles
.button {
padding: $cx-space-button-padding-block $cx-space-button-padding-inline;
background-color: $cx-color-context-primary-bg-solid;
color: $cx-color-context-primary-fg-solid;
border-radius: $cx-border-radius-button-main;
font: $cx-font-button-medium;
}
Import Selectively (SCSS)
Import only what you need for smaller bundle sizes:
// settings.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
// component.scss
.card {
background: $cx-color-context-default-bg-main;
padding: $cx-space-base-16;
border-radius: $cx-border-radius-base-8;
}
With Custom Prefix
Change the token prefix by overriding the $prefix variable:
// Override default prefix before import
$prefix: my- !default;
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
// Now tokens use your prefix
.element {
margin: $my-space-base-16;
}
Theme Switching
Chassis supports light and dark modes through separate token files.
Data Attribute Method
Use data attributes to switch themes (recommended):
// Import both themes
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
// Default to light mode
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
.component {
background: $cx-color-context-default-bg-main;
color: $cx-color-context-default-fg-main;
}
// Override for dark mode
[data-cx-theme="dark"] {
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-dark";
.component {
background: $cx-color-context-default-bg-main;
color: $cx-color-context-default-fg-main;
}
}
CSS Custom Properties Method
Convert SCSS variables to CSS custom properties for runtime theme switching:
// theme.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
:root {
--bg-main: #{$cx-color-context-default-bg-main};
--fg-main: #{$cx-color-context-default-fg-main};
--primary-bg: #{$cx-color-context-primary-bg-solid};
// ... map other tokens
}
[data-cx-theme="dark"] {
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-dark";
--bg-main: #{$cx-color-context-default-bg-main};
--fg-main: #{$cx-color-context-default-fg-main};
--primary-bg: #{$cx-color-context-primary-bg-solid};
// ... map other tokens
}
// Use in components
.component {
background: var(--bg-main);
color: var(--fg-main);
}
JavaScript Theme Switcher
Toggle theme with JavaScript:
// Set theme
document.documentElement.setAttribute('data-cx-theme', 'dark');
// Toggle theme
const currentTheme = document.documentElement.getAttribute('data-cx-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-cx-theme', newTheme);
// Save preference
localStorage.setItem('cx-theme', newTheme);
// Restore on load
const savedTheme = localStorage.getItem('cx-theme') || 'light';
document.documentElement.setAttribute('data-cx-theme', savedTheme);
Responsive Design
Chassis provides screen-specific tokens for responsive layouts.
Breakpoint Tokens
Import different screen sizes based on your responsive strategy:
// Base and large screen (desktop-first)
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-large";
// Medium screens (tablets)
@media (max-width: 992px) {
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-medium";
.container {
padding: $cx-space-container-padding-block $cx-space-container-padding-inline;
}
}
// Small screens (mobile)
@media (max-width: 768px) {
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-small";
.container {
padding: $cx-space-container-padding-block $cx-space-container-padding-inline;
}
}
Mobile-First Approach
// Base and small screen (mobile-first)
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-small";
.heading {
font-size: $cx-typography-fontSize-text-xlarge;
}
// Medium screens and up
@media (min-width: 768px) {
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-medium";
.heading {
font-size: $cx-typography-fontSize-text-2xlarge;
}
}
// Large screens and up
@media (min-width: 992px) {
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-large";
.heading {
font-size: $cx-typography-fontSize-text-3xlarge;
}
}
Bundler Configuration
Vite
Vite works seamlessly with SCSS imports:
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
// Additional SCSS options
additionalData: `$prefix: cx- !default;`
}
}
}
});
Import tokens in your components:
<!-- Vue SFC -->
<style lang="scss">
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
.button {
background: $cx-color-context-primary-bg-solid;
padding: $cx-space-button-padding-block;
}
</style>
Webpack
Configure Webpack to handle SCSS imports:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sassOptions: {
includePaths: ['node_modules']
}
}
}
]
}
]
}
};
Import in your entry file:
// index.js
import './styles/main.scss';
// styles/main.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
Next.js
Next.js supports SCSS out of the box:
npm install sass
Import tokens globally:
// pages/_app.js
import '../styles/tokens.scss';
import '../styles/globals.scss';
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}
// styles/tokens.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-large";
Use in CSS Modules:
// components/Button.module.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
.button {
padding: $cx-space-button-padding-block $cx-space-button-padding-inline;
background: $cx-color-context-primary-bg-solid;
}
Astro
Astro has built-in SCSS support:
---
// Component.astro
---
<div class="card">
<slot />
</div>
<style lang="scss">
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
.card {
background: $cx-color-context-default-bg-main;
padding: $cx-space-base-16;
border-radius: $cx-border-radius-base-8;
}
</style>
Global styles:
// astro.config.mjs
export default {
vite: {
css: {
preprocessorOptions: {
scss: {
additionalData: `
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
`
}
}
}
}
};
Parcel
Parcel automatically handles SCSS:
// src/styles/main.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
body {
background: $cx-color-context-default-bg-main;
color: $cx-color-context-default-fg-main;
}
<!-- index.html -->
<link rel="stylesheet" href="./src/styles/main.scss">
Rollup
Configure Rollup with SCSS plugin:
npm install rollup-plugin-scss sass --save-dev
// rollup.config.js
import scss from 'rollup-plugin-scss';
export default {
plugins: [
scss({
outputStyle: 'compressed',
includePaths: ['node_modules']
})
]
};
Advanced Patterns
Create a Token Layer
Create an abstraction layer for easier token management:
// _tokens.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-large";
// Create semantic aliases
$color-background: $cx-color-context-default-bg-main;
$color-text: $cx-color-context-default-fg-main;
$color-primary: $cx-color-context-primary-bg-solid;
$spacing-unit: $cx-space-base-8;
$border-radius: $cx-border-radius-base-8;
// Export for use in components
// component.scss
@import "tokens";
.button {
background: $color-primary;
padding: calc($spacing-unit * 2);
border-radius: $border-radius;
}
CSS-in-JS Integration
Convert tokens to JavaScript objects for CSS-in-JS libraries:
// tokens.js
import tokens from '@chassis-ui/tokens/dist/web/docs/chassis/main.scss';
export const theme = {
colors: {
primary: 'var(--cx-color-context-primary-bg-solid)',
background: 'var(--cx-color-context-default-bg-main)',
},
spacing: {
small: 'var(--cx-space-base-8)',
medium: 'var(--cx-space-base-16)',
large: 'var(--cx-space-base-24)',
}
};
Use with styled-components:
import styled from 'styled-components';
import { theme } from './tokens';
const Button = styled.button`
background: ${theme.colors.primary};
padding: ${theme.spacing.medium};
`;
Dynamic Theme Switching
Build a complete theme system:
// theme.ts
type Theme = 'light' | 'dark';
class ThemeManager {
private current: Theme = 'light';
constructor() {
this.load();
this.applyMediaQuery();
}
set(theme: Theme) {
this.current = theme;
document.documentElement.setAttribute('data-cx-theme', theme);
localStorage.setItem('cx-theme', theme);
}
toggle() {
this.set(this.current === 'light' ? 'dark' : 'light');
}
private load() {
const saved = localStorage.getItem('cx-theme') as Theme;
if (saved) {
this.set(saved);
}
}
private applyMediaQuery() {
const query = window.matchMedia('(prefers-color-scheme: dark)');
if (!localStorage.getItem('cx-theme')) {
this.set(query.matches ? 'dark' : 'light');
}
query.addEventListener('change', (e) => {
if (!localStorage.getItem('cx-theme')) {
this.set(e.matches ? 'dark' : 'light');
}
});
}
}
export const themeManager = new ThemeManager();
Build Optimization
Tree Shaking
Import only needed tokens to reduce bundle size:
// Instead of importing entire files
// @import "@chassis-ui/tokens/dist/web/docs/chassis/main";
// Import specific token categories
@use "@chassis-ui/tokens/dist/web/docs/chassis/main" with (
$cx-color-context-default-bg-main: true,
$cx-space-base-16: true
);
Purge Unused Tokens
Use PurgeCSS to remove unused tokens:
// postcss.config.js
module.exports = {
plugins: [
require('@fullhuman/postcss-purgecss')({
content: ['./src/**/*.{js,jsx,ts,tsx,vue,html}'],
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
})
]
};
Code Splitting
Split tokens by route or component:
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
tokens: {
test: /@chassis-ui\/tokens/,
name: 'tokens',
chunks: 'all'
}
}
}
}
};
Best Practices
Do's
✅ Import tokens once: Import at the root level and reuse throughout your app
✅ Use semantic tokens: Prefer context tokens (color.context.primary.*) over base tokens (color.palette.primary.*)
✅ Create abstractions: Build a token layer for your specific use cases
✅ Respect theme modes: Always test in both light and dark modes
✅ Use responsive tokens: Import screen-specific tokens for better responsive design
Don'ts
❌ Don't hardcode values: Always use tokens instead of magic numbers
❌ Don't import everywhere: Avoid importing token files in every component
❌ Don't override tokens directly: Create custom variables that reference tokens
❌ Don't mix unit systems: Stick to one unit system (rem, px, or vw) per project
❌ Don't ignore accessibility: Use tokens that maintain proper contrast ratios
Troubleshooting
Import Errors
Problem: Cannot resolve '@chassis-ui/tokens'
Solution: Ensure the package is installed and your bundler is configured to resolve node_modules:
// vite.config.js
export default {
resolve: {
alias: {
'@chassis-ui/tokens': path.resolve(__dirname, 'node_modules/@chassis-ui/tokens')
}
}
};
SCSS Compilation Errors
Problem: Undefined variable errors
Solution: Ensure imports are in the correct order (main → color → number):
// Correct order
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
@import "@chassis-ui/tokens/dist/web/docs/chassis/number-large";
Theme Not Switching
Problem: Theme changes don't apply
Solution: Ensure data attribute is on the root element and selectors have proper specificity:
:root[data-cx-theme="dark"] {
// Dark theme overrides
}
Large Bundle Size
Problem: Token imports bloat bundle size
Solution: Use code splitting, tree shaking, and import only needed tokens
Example Projects
Simple Static Site
// styles/main.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
body {
font-family: $cx-typography-fontFamily-text;
background: $cx-color-context-default-bg-main;
color: $cx-color-context-default-fg-main;
padding: $cx-space-base-16;
}
.button {
padding: $cx-space-button-padding-block $cx-space-button-padding-inline;
background: $cx-color-context-primary-bg-solid;
color: $cx-color-context-primary-fg-solid;
border-radius: $cx-border-radius-button-main;
border: $cx-border-width-button-main solid transparent;
font: $cx-font-button-medium;
cursor: pointer;
&:hover {
background: $cx-color-context-primary-bg-hover;
}
}
React Application
// src/styles/tokens.scss
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
:root {
--bg: #{$cx-color-context-default-bg-main};
--fg: #{$cx-color-context-default-fg-main};
--primary: #{$cx-color-context-primary-bg-solid};
--radius: #{$cx-border-radius-base-8};
}
[data-cx-theme="dark"] {
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-dark";
--bg: #{$cx-color-context-default-bg-main};
--fg: #{$cx-color-context-default-fg-main};
--primary: #{$cx-color-context-primary-bg-solid};
}
// src/App.jsx
import './styles/tokens.scss';
import { useState } from 'react';
function App() {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
document.documentElement.setAttribute('data-cx-theme', newTheme);
};
return (
<div className="app">
<button onClick={toggleTheme}>
Toggle {theme === 'light' ? 'Dark' : 'Light'} Mode
</button>
</div>
);
}
Vue Application
<!-- App.vue -->
<template>
<div :data-cx-theme="theme">
<button @click="toggleTheme">Toggle Theme</button>
<slot />
</div>
</template>
<script setup>
import { ref } from 'vue';
const theme = ref('light');
const toggleTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
};
</script>
<style lang="scss">
@import "@chassis-ui/tokens/dist/web/docs/chassis/main";
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-light";
:root {
background: $cx-color-context-default-bg-main;
color: $cx-color-context-default-fg-main;
}
[data-cx-theme="dark"] {
@import "@chassis-ui/tokens/dist/web/docs/chassis/color-dark";
background: $cx-color-context-default-bg-main;
color: $cx-color-context-default-fg-main;
}
</style>
Next Steps
- Learn about token structure and naming
- Understand token transformation and build process
- Explore design token categories