@swisper.ai/design-system
v0.0.4
Published
Echo DS design tokens: CSS variables, the Tailwind v4 theme and the MUI theme
Readme
@swisper.ai/design-system
Echo DS design tokens: CSS variables, the Tailwind v4 theme and the MUI theme. It ships stylesheets
and theme objects, not components: those are in @swisper.ai/ui and the other Echo DS packages.
The Tailwind entry needs a Tailwind v4 build in the app, and the MUI theme needs @mui/material.
Boundary
Code belongs here if it is a design token or is generated from one: the Figma (Tokens Studio)
export, the CSS variables Style Dictionary builds from it, the Tailwind @theme that maps those
variables to utilities, and the MUI themes. The list of files Tailwind scans belongs in
@swisper.ai/tailwind-config, icons in @swisper.ai/icons, and components in @swisper.ai/ui.
Install
npm install @swisper.ai/design-system| Peer | Range | Why |
| --------------- | --------- | --------------------------------------------------------------------------------- |
| @mui/material | >=7.0.0 | ./mui-theme builds its themes with createTheme. The CSS entries don't use it. |
tailwindcss 4 is a regular dependency, and src/tailwind.css starts with @import 'tailwindcss',
so the app's CSS doesn't import Tailwind again. MUI itself needs @emotion/react and
@emotion/styled.
Setup
Add Tailwind v4 to the app's build, for example
npm install -D @tailwindcss/viteandplugins: [tailwindcss()]in the Vite config.In the app's CSS entry, import the theme in place of
@import 'tailwindcss':@import '@swisper.ai/design-system/src/tailwind.css';Style with token utilities:
export function Panel() { return <div className="rounded-md bg-paper-elevation-1 p-16 text-text-primary">Ready</div>; }If the app uses MUI components, give them the same tokens:
import { ThemeProvider } from '@mui/material/styles'; import { darkTheme } from '@swisper.ai/design-system/mui-theme'; <ThemeProvider theme={darkTheme}> <App /> </ThemeProvider>;
Styles
There are two entries. Use one, not both.
@swisper.ai/design-system/src/tailwind.cssis Tailwind source: it importstailwindcss, the token CSS variables and the@themeblock, so utilities such asbg-paper-elevation-1exist in the app's own Tailwind build. Use it in any app that runs Tailwind.@swisper.ai/design-system/dist/tailwind.cssis prebuilt and minified: Tailwind's preflight plus every token as a CSS variable, but only the few utilities this package uses itself. Use it when the app doesn't run Tailwind and only readsvar(--…)values.
Loading the prebuilt file next to the app's own Tailwind build declares preflight and the tokens twice, and whichever loads last overrides the app's base styles.
Spacing
A number in a spacing class is pixels, not Tailwind's 4px steps: gap-8 is 8px and p-16 is 16px.
The scale is 0, 1, 2, 3, 4, 6, 7, 8, 10, 12, 13, 16, 20, 24, 32, 40 and 48. A number off the scale
falls back to Tailwind's default, so p-5 is 20px.
Font sizes
Font-size tokens (--st-font-size-*, --ct-*-font-size) are in rem at a 16px base: 14px in Figma
is 0.875rem. Text therefore follows the root font size, so an app's text-size setting sets
font-size on <html>. Every other number token, spacing included, stays in px.
Light theme and fonts
src/tailwind.css defines a theme-light: variant, which applies inside an element with
data-theme="light". The tokens name the Noto Sans, Hanken Grotesk, Red Hat Display and IBM Plex
Mono font families, but the package loads no font files: the app loads them, for example from
Google Fonts.
API
| Export | Why it exists |
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| @swisper.ai/design-system/src/tailwind.css | The Tailwind v4 theme: token CSS variables, the @theme that turns them into utilities, Echo DS breakpoints and the theme-light: variant. |
| @swisper.ai/design-system/dist/tailwind.css | The tokens as plain CSS variables (with preflight) for apps that don't build Tailwind. |
| darkTheme, lightTheme from @swisper.ai/design-system/mui-theme | MUI themes built from the same tokens (palette, Noto Sans typography, 8px spacing, radius, icon sizes), so MUI components match the Tailwind-styled ones. |
| paperXMargin, paperYMargin, doublePaperXMargin, doublePaperYMargin (mui-theme) | The page margins in pixels (20, and 40 for both sides), for layouts that compute sizes in JavaScript. |
| tertiaryColor (mui-theme) | The tertiary color (#B6C2D1) as a string, for code that needs it outside CSS. |
Importing ./mui-theme also adds steel, blue and lagoon to MUI's PaletteOptions type. The
Echo DS Storybook shows every color token and the typography.
Troubleshooting
| Symptom | Cause | Fix |
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| Layout is right, but colors or radii are wrong or missing | The design-system theme isn't loaded, so theme utilities such as bg-paper-elevation-1 are empty | Import @swisper.ai/design-system/src/tailwind.css before any package's tailwind.css |
| Your own base styles (fonts, headings, resets) get overridden | The prebuilt dist/tailwind.css (or a package's prebuilt index.css) is loaded next to your own Tailwind build, and its preflight wins | Use one of the two: drop the prebuilt file and import src/tailwind.css |
| Spacing looks wrong after upgrading (huge gaps, tiny icons) | A number in a spacing class is pixels: gap-8 is 8px, not Tailwind's default 32px | Write the pixel value you want, from the scale under Styles |
| p-5 or gap-64 is bigger than expected | The number isn't on the token scale, so Tailwind's 4px steps apply | Use a number on the scale, or an arbitrary value such as p-[5px] |
| Utilities such as bg-paper-elevation-1 produce no CSS | The app loads dist/tailwind.css, which carries the variables but not the utilities | Import src/tailwind.css from the app's Tailwind entry |
| Package subpath './dist/css/tokens.css' is not defined by "exports" | Only ./src/tailwind.css, ./dist/tailwind.css and ./mui-theme are public entries | Import one of those; both CSS entries include every token variable |
| Text renders in a fallback font | The package names font families but ships no font files | Load Noto Sans, Hanken Grotesk, Red Hat Display and IBM Plex Mono in the app |
| Cannot find module '@mui/material/styles' when importing mui-theme | @mui/material isn't installed | npm install @mui/material @emotion/react @emotion/styled |
| Styles are missing or doubled, or the MUI theme doesn't apply | The app resolves two copies of @emotion/react or @mui/material | Add them to resolve.dedupe in the Vite config, next to react and react-dom |
| ERR_MODULE_NOT_FOUND for dist/js/tokens when a test imports mui-theme | dist/ uses extensionless imports that only a bundler resolves, and Vitest externalizes it | Set server.deps.inline: [/@swisper\.ai\//] in the Vitest config |
