@fastwork/xosmoz-theme
v1.0.1
Published
Xosmoz Theme - Design tokens and theming system for Xosmoz
Readme
@fastwork/xosmoz-theme
Design tokens and theming system for the Xosmoz design system. Uses OKLCH color space for perceptually uniform colors. Supports light and dark themes via CSS custom properties with data-theme attribute switching.
Installation
npm install @fastwork/xosmoz-themeQuick Start
/* Base styles: CSS reset, font imports, typography/spacing/shadow tokens */
@import '@fastwork/xosmoz-theme/base.css';
/* All themes (light + dark) */
@import '@fastwork/xosmoz-theme/themes.css';
/* OR import a specific theme only */
@import '@fastwork/xosmoz-theme/themes/light.css';
/* @import '@fastwork/xosmoz-theme/themes/dark.css'; */Theme Switching
Set the theme via the data-theme attribute on the <html> element. Light theme is the default (no attribute needed).
<!-- Light theme (default) -->
<html>...</html>
<!-- Dark theme -->
<html data-theme="dark">...</html>// Switch theme at runtime
document.documentElement.setAttribute('data-theme', 'dark');
// Remove attribute to return to light (default)
document.documentElement.removeAttribute('data-theme');
// Persist across sessions
function setTheme(name) {
document.documentElement.setAttribute('data-theme', name);
localStorage.setItem('theme', name);
}
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);CSS Variables Reference
All variables use the --xz- prefix.
Base Colors
Surface and layout colors that adapt between light and dark themes.
| Variable | Purpose |
|----------|---------|
| --xz-color-surface-50 | Base white surface |
| --xz-color-surface-100 | Primary page background |
| --xz-color-surface-200 | Elevated surface (cards, modals) |
| --xz-color-surface-300 | Table headers, sidebars |
| --xz-color-surface-400 | Popovers, tooltips |
| --xz-color-text-100 | Primary text |
| --xz-color-text-200 | Secondary/muted text (70% opacity) |
| --xz-color-text-300 | Tertiary/disabled text (60% opacity) |
| --xz-color-bg-100 | Extreme base background (near-black in light, near-white in dark) |
| --xz-color-bg-200 | Darker base background |
| --xz-color-text-fg | Text on bg-100 (white in light, black in dark) |
| --xz-color-line-50 | Subtle borders |
| --xz-color-line-100 | Default borders |
| --xz-color-line-200 | Strong/emphasized borders |
| --xz-color-line-300 | Strongest borders |
Semantic Colors
Eight semantic categories: primary, danger, success, warning, info, neutral, orange, purple.
Each category follows the same token structure — replace {name} with the category:
| Variable | Purpose |
|----------|---------|
| --xz-color-{name}-soft-100 | Lightest tinted background (badges, highlights) |
| --xz-color-{name}-soft-200 | Stronger tinted background (hover states) |
| --xz-color-{name}-soft-solid-100 | Light color-mixed background (solid, no transparency) |
| --xz-color-{name}-soft-solid-200 | Stronger color-mixed background (solid, no transparency) |
| --xz-color-{name}-line-100 | Subtle colored border |
| --xz-color-{name}-line-200 | Default colored border (input focus) |
| --xz-color-{name}-line-300 | Strong colored border (active states) |
| --xz-color-{name}-bg-100 | Solid fill (buttons, tags) |
| --xz-color-{name}-bg-200 | Darker solid fill (hover state) |
| --xz-color-{name}-text-fg | Text on solid backgrounds — pair with bg-100/bg-200 (typically white) |
| --xz-color-{name}-text-100 | Colored text on surfaces (links, labels) |
| --xz-color-{name}-text-200 | Darker colored text on surfaces |
Usage example:
/* Primary button */
.btn-primary {
background: var(--xz-color-primary-bg-100);
color: var(--xz-color-primary-text-fg); /* white text on solid bg */
}
.btn-primary:hover {
background: var(--xz-color-primary-bg-200);
}
/* Soft badge */
.badge-success {
background: var(--xz-color-success-soft-100);
color: var(--xz-color-success-text-100);
border: 1px solid var(--xz-color-success-line-100);
}Alpha Overlays
Three alpha overlay scales with steps from 100 (10% opacity) to 1000 (100% opacity):
--xz-color-black-alpha-{100-1000} /* black with increasing opacity */
--xz-color-white-alpha-{100-1000} /* white with increasing opacity */
--xz-color-overlay-{100-1000} /* overlay (black-based) with increasing opacity */Raw Color Palettes
Single base color per palette. Available palettes: fastwork, gray, green, yellow, red, orange, purple, cyan.
--xz-color-{palette} /* palette base color */Each palette color is defined using OKLCH
Typography
Font sizes (50–1600 numeric scale):
| Variable | Value |
|----------|-------|
| --xz-font-size-50 | 0.5rem / 8px |
| --xz-font-size-100 | 0.625rem / 10px |
| --xz-font-size-200 | 0.75rem / 12px |
| --xz-font-size-300 | 0.875rem / 14px |
| --xz-font-size-400 | 1rem / 16px |
| --xz-font-size-500 | 1.125rem / 18px |
| --xz-font-size-600 | 1.25rem / 20px |
| --xz-font-size-700 | 1.5rem / 24px |
| --xz-font-size-800 | 1.625rem / 26px |
| --xz-font-size-900 | 2rem / 32px |
| --xz-font-size-1000 | 2.375rem / 38px |
| --xz-font-size-1100 | 2.5rem / 40px |
| --xz-font-size-1200 | 2.6875rem / 43px |
| --xz-font-size-1300 | 3rem / 48px |
| --xz-font-size-1400 | 3.5rem / 56px |
| --xz-font-size-1500 | 4rem / 64px |
| --xz-font-size-1600 | 4.5rem / 72px |
Font families:
--xz-font-family-primary /* "Google Sans" + system sans-serif stack */
--xz-font-family-secondary /* "Google Sans" + "Fastwork" + "Noto Sans Thai" + system fallbacks */Line heights:
--xz-line-height-100pct /* 1 */
--xz-line-height-125pct /* 1.25 */
--xz-line-height-135pct /* 1.35 */
--xz-line-height-150pct /* 1.5 */
--xz-line-height-165pct /* 1.65 */
--xz-line-height-200pct /* 2 */Font shorthand tokens — headings are responsive (scale down on mobile ≤768px), other tokens use fixed sizes:
/* Headings — secondary font, bold, responsive */
--xz-font-heading1 /* 72px desktop / 48px mobile */
--xz-font-heading2 /* 64px desktop / 43px mobile */
--xz-font-heading3 /* 56px desktop / 38px mobile */
--xz-font-heading4 /* 48px desktop / 32px mobile */
--xz-font-heading5 /* 40px desktop / 26px mobile */
--xz-font-heading6 /* 32px desktop / 24px mobile */
/* Titles — primary font, bold */
--xz-font-title1 /* 24px */
--xz-font-title2 /* 20px */
--xz-font-title3 /* 18px */
--xz-font-title4 /* 16px */
/* Subtitles — primary font, bold or regular */
--xz-font-subtitle1-bold
--xz-font-subtitle1-regular /* 16px */
--xz-font-subtitle2-bold
--xz-font-subtitle2-regular /* 14px */
--xz-font-subtitle3-bold
--xz-font-subtitle3-regular /* 12px */
/* Body — primary font, regular */
--xz-font-body1 /* 16px */
--xz-font-body2 /* 14px */
--xz-font-body3 /* 12px */
--xz-font-body4 /* 10px */Usage: font: var(--xz-font-heading1);
Box Shadows
--xz-box-shadow-100 /* 0 1px 2px — subtle */
--xz-box-shadow-200 /* 0 2px 6px — small */
--xz-box-shadow-300 /* 0 4px 16px — medium */
--xz-box-shadow-400 /* 0 8px 20px — large */JavaScript/TypeScript API
Theme Objects
import { lightTheme, darkTheme, themes, getTheme, getThemeNames } from '@fastwork/xosmoz-theme';
// Access raw palette colors
lightTheme.palette.fastwork.value // 'oklch(0.57 0.237 260.608)'
// Access semantic colors
lightTheme.colors.primary.bg[100] // solid fill color
lightTheme.colors.primary.fg[100] // 'oklch(1 0 0 / 1)' — white for text on solid bg
lightTheme.colors.primary.text[100] // colored text
lightTheme.colors.orange.bg[100] // orange solid fill
lightTheme.colors.purple.soft[100] // purple tinted background
// Access base tokens
lightTheme.colors.surface[200] // card background
lightTheme.colors.text[100] // primary text
// Access box shadows
lightTheme.boxShadows[200] // '0 2px 6px 0 rgba(0, 0, 0, 0.10)'
// Get theme by name
const theme = getTheme('dark');
// List available themes
const names = getThemeNames(); // ['light', 'dark']Design Tokens
import { fontSize, fontWeight, fontFamily, lineHeight, font, typography } from '@fastwork/xosmoz-theme/tokens';
fontSize[400] // '1rem'
fontSize[700] // '1.5rem'
fontWeight[700] // 700
fontFamily.primary // "Google Sans" + system sans-serif stack
fontFamily.secondary // "Google Sans" + "Fastwork" + "Noto Sans Thai" + fallbacks
lineHeight['150pct'] // '1.5'
// Semantic font tokens
font.heading1 // { fontFamily, fontSize: { desktop, mobile }, fontWeight, lineHeight }
font.title2
font.subtitle1Bold
font.body1
// All typography combined
typography.fontSize
typography.fontFamily
typography.fontTypes
import type {
ThemeConfig,
ThemeName,
ThemeRegistry,
ColorToken,
TypographyToken,
TypographyScale,
FontWeights,
HeadingTokens,
TitleTokens,
SubtitleTokens,
BodyTokens,
Theme,
} from '@fastwork/xosmoz-theme';Custom Themes
Override any CSS variable for a custom theme:
[data-theme="brand"] {
--xz-color-surface-100: oklch(1.00 0 0);
--xz-color-surface-200: oklch(0.98 0.005 260);
--xz-color-text-100: oklch(0.20 0.006 285);
--xz-color-line-50: oklch(0.95 0 1 / 0.95);
--xz-color-primary-bg-100: oklch(0.58 0.25 30);
--xz-color-primary-text-fg: oklch(1 0 0 / 0.95);
--xz-color-primary-text-100: oklch(0.58 0.25 30);
/* override other variables as needed */
}Then activate it:
<html data-theme="brand">...</html>Common Patterns
Card
.card {
background: var(--xz-color-surface-200);
color: var(--xz-color-text-100);
border: 1px solid var(--xz-color-line-50);
border-radius: 0.75rem;
box-shadow: var(--xz-box-shadow-200);
}Primary button
.btn-primary {
background: var(--xz-color-primary-bg-100);
color: var(--xz-color-primary-text-fg);
font: var(--xz-font-subtitle1-bold);
border: none;
border-radius: 0.5rem;
}
.btn-primary:hover {
background: var(--xz-color-primary-bg-200);
}Outline button
.btn-outline {
background: transparent;
color: var(--xz-color-primary-text-100);
border: 1px solid var(--xz-color-primary-line-200);
}Alert
.alert-success {
background: var(--xz-color-success-soft-100);
color: var(--xz-color-success-text-100);
border: 1px solid var(--xz-color-success-line-100);
}
.alert-danger {
background: var(--xz-color-danger-bg-100);
color: var(--xz-color-danger-text-fg);
}Form input
.input {
background: var(--xz-color-surface-100);
color: var(--xz-color-text-100);
border: 1px solid var(--xz-color-line-100);
font: var(--xz-font-body1);
}
.input:focus {
border-color: var(--xz-color-primary-line-200);
box-shadow: 0 0 0 3px var(--xz-color-primary-soft-100);
}Muted text
.text-muted { color: var(--xz-color-text-200); }
.text-disabled { color: var(--xz-color-text-300); }CSS Files
| Import path | Contents |
|-------------|----------|
| @fastwork/xosmoz-theme/base.css | Font imports, CSS reset, non-color tokens (typography, spacing, borders, shadows) |
| @fastwork/xosmoz-theme/themes.css | All themes (light + dark) |
| @fastwork/xosmoz-theme/themes/light.css | Light theme colors only |
| @fastwork/xosmoz-theme/themes/dark.css | Dark theme colors only |
| @fastwork/xosmoz-theme/llms.txt | LLM context file for AI tooling |
Development
# Build the package (TypeScript + CSS)
npm run build
# Watch mode
npm run dev
# Lint
npm run lint
# Remove dist/
npm run cleanLicense
MIT
