Design Token System - Single Source of Truth
Status: β
Complete
Date: October 11, 2025
Branch: feat/tailwind-integration
Problem Statement
Section titled βProblem StatementβYou asked: βHow will this work when we change the design? Can we set it up to change the design theme for a particular app in one place and have that theme apply to the web and to the mobile apps?β
Answer: Yes! Hereβs how it works:
Solution Architecture
Section titled βSolution Architectureβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Design Tokens (Single Source of Truth) ββ packages/theme/src/tokens.ts ββ ββ - Colors (primary, secondary, semantic) ββ - Typography (families, sizes, weights) ββ - Spacing (4px base grid) ββ - Border radius, shadows, z-index, breakpoints βββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββ β βββββββββββ΄ββββββββββ β β βΌ βΌββββββββββββββββββ βββββββββββββββββββ Tailwind β β Brand-Specific ββ Preset β β Theme Override ββ (Web/Mobile) β β βββββββββββ¬ββββββββ ββββββββββ¬ββββββββ β β β ββββββββββββββββ β β βΌ βΌββββββββββββββββββββββββββββββββββββββββ Individual App Configs ββ ββ β’ Pinkguest (pink primary color) ββ β’ Orangeguest (orange primary) ββ β’ RoomLGBT (purple primary) ββββββββββββββββββββββββββββββββββββββββHow It Works
Section titled βHow It Worksβ1. Define Design Tokens Once
Section titled β1. Define Design Tokens OnceβFile: packages/theme/src/tokens.ts
// This is your SINGLE SOURCE OF TRUTHexport const colors = { primary: { 50: '#f0f9ff', 500: '#0ea5e9', // Main primary color 900: '#0c4a6e', }, // ... all other colors};
export const typography = { families: { sans: ['Inter', 'system-ui', 'sans-serif'], }, sizes: { base: { size: '1rem', lineHeight: '1.5rem' }, },};2. Create Brand-Specific Overrides (Optional)
Section titled β2. Create Brand-Specific Overrides (Optional)βFile: packages/theme/src/brands.ts
// Pinkguest overrides ONLY the primary colorexport const pinkguestTheme = createBrandTheme({ colors: { primary: { 50: '#fdf2f8', 500: '#ec4899', // Pink instead of blue! 900: '#831843', }, },});
// Everything else (typography, spacing, etc.) inherits from base3. Tailwind Preset Consumes Tokens
Section titled β3. Tailwind Preset Consumes TokensβFile: packages/config/tailwind-preset.js
// Import design tokensconst tokens = require('@cloudalt-frontend/theme');
module.exports = { theme: { extend: { colors: tokens.colors, // β Design tokens flow here fontFamily: tokens.typography.families, fontSize: convertFontSizes(tokens.typography.sizes), spacing: tokens.spacing, // ... all other tokens }, },};4. Apps Use Brand-Specific Presets
Section titled β4. Apps Use Brand-Specific PresetsβFile: apps/stay_match/pinkguest/mobile/tailwind.config.js
// Option A: Base theme (blue primary)module.exports = { presets: [require('@cloudalt-frontend/config/tailwind-preset')], content: ['./src/**/*.{js,jsx,ts,tsx}'],};
// Option B: Brand-specific theme (pink primary)const { createBrandPreset } = require('@cloudalt-frontend/config/tailwind-preset');
module.exports = { presets: [createBrandPreset('pinkguest')], // β Brand name here! content: ['./src/**/*.{js,jsx,ts,tsx}'],};Usage Examples
Section titled βUsage ExamplesβExample 1: Change Global Primary Color
Section titled βExample 1: Change Global Primary ColorβScenario: You want to change the primary color for ALL apps.
Solution: Edit ONE file:
export const colors = { primary: { 50: '#fef2f2', // Changed from blue to red 500: '#ef4444', // New primary red 900: '#7f1d1d', },};Result: All apps (web and mobile) using the base theme now have red primary color.
Example 2: Change Brand-Specific Color
Section titled βExample 2: Change Brand-Specific ColorβScenario: You want Pinkguest to have a different shade of pink.
Solution: Edit ONE file:
export const pinkguestTheme = createBrandTheme({ colors: { primary: { 500: '#db2777', // Darker pink }, },});Result: Only Pinkguest apps change. All other apps unaffected.
Example 3: Add New Brand Theme
Section titled βExample 3: Add New Brand ThemeβScenario: Youβre launching βGreenhostβ with a green theme.
Solution: Add to packages/theme/src/brands.ts:
export const greenhostTheme = createBrandTheme({ colors: { primary: { 50: '#f0fdf4', 500: '#22c55e', // Green 900: '#14532d', }, },});
export const brandThemes = { pinkguest: pinkguestTheme, orangeguest: orangeguestTheme, greenhost: greenhostTheme, // β New brand};Then in Greenhostβs tailwind config:
module.exports = { presets: [createBrandPreset('greenhost')], content: ['./src/**/*.{js,jsx,ts,tsx}'],};Example 4: Change Typography Globally
Section titled βExample 4: Change Typography GloballyβScenario: Design wants to switch from Inter to Poppins.
Solution: Edit ONE file:
export const typography = { families: { sans: ['Poppins', 'system-ui', 'sans-serif'], // Changed! },};Result: All apps (web and mobile) now use Poppins.
Example 5: Adjust Spacing Scale
Section titled βExample 5: Adjust Spacing ScaleβScenario: Design wants tighter spacing across all apps.
Solution: Edit ONE file:
export const spacing = { 1: '0.2rem', // Changed from 0.25rem 2: '0.4rem', // Changed from 0.5rem 3: '0.6rem', // Changed from 0.75rem // ...};Result: All apps get new spacing scale automatically.
Component Usage
Section titled βComponent UsageβWeb Component (React)
Section titled βWeb Component (React)β// Automatically uses design tokens via Tailwindfunction Button() { return ( <button className="bg-primary-500 text-white px-4 py-2 rounded-lg"> Click Me </button> );}Mobile Component (React Native)
Section titled βMobile Component (React Native)β// Same Tailwind classes work via NativeWind!import { View, Text, Pressable } from 'react-native';
function Button() { return ( <Pressable className="bg-primary-500 px-4 py-2 rounded-lg"> <Text className="text-white font-semibold"> Click Me </Text> </Pressable> );}Direct Token Usage (if needed)
Section titled βDirect Token Usage (if needed)β// You can also import tokens directlyimport { colors } from '@cloudalt-frontend/theme';
const styles = { backgroundColor: colors.primary[500],};Testing Changes
Section titled βTesting ChangesβStep 1: Edit Design Tokens
Section titled βStep 1: Edit Design Tokensβ# Edit the tokens filecode packages/theme/src/tokens.tsStep 2: Changes Propagate Automatically
Section titled βStep 2: Changes Propagate AutomaticallyβNo rebuild needed! The tokens are imported at build time.
Step 3: Test in Storybook (Phase 1.3)
Section titled βStep 3: Test in Storybook (Phase 1.3)β# Launch Storybook to see all components with new tokensyarn nx run storybook:storybookStep 4: Test in Mobile App
Section titled βStep 4: Test in Mobile Appβ# Clear Metro cache to pick up changesyarn nx run pinkguest-mobile:start --clearMigration Path
Section titled βMigration PathβPhase 1: Infrastructure (Current)
Section titled βPhase 1: Infrastructure (Current)β- β
Design tokens defined in
packages/theme - β Tailwind preset consumes tokens
- β Brand-specific overrides system
- β Documentation complete
Phase 2: Apply to Pinkguest
Section titled βPhase 2: Apply to Pinkguestβ- π
Add
tailwind.config.jsto Pinkguest mobile - π Convert components to use Tailwind classes
- π Test thoroughly
Phase 3: Extract to Shared Components
Section titled βPhase 3: Extract to Shared Componentsβ- π
Move common components to
packages/ui - π Components already use design tokens via Tailwind
- π Reusable across all brands
Phase 4: Rollout to Other Apps
Section titled βPhase 4: Rollout to Other Appsβ- π Copy tailwind config to each app
- π Use brand-specific preset per app
- π Gradual migration of components
Benefits
Section titled βBenefitsβ1. Single Point of Control
Section titled β1. Single Point of ControlβChange design tokens once, all apps update automatically.
2. Brand Consistency
Section titled β2. Brand ConsistencyβEach brand can override specific tokens while keeping shared values.
3. Type Safety
Section titled β3. Type SafetyβTypeScript types ensure tokens are used correctly.
4. Works Everywhere
Section titled β4. Works EverywhereβSame tokens work in:
- Web apps (Tailwind CSS)
- Mobile apps (NativeWind)
- Storybook (design documentation)
- Direct imports (when needed)
5. Design-Dev Sync
Section titled β5. Design-Dev SyncβExport tokens from Figma β Update tokens.ts β All apps updated.
Advanced: Figma Integration
Section titled βAdvanced: Figma IntegrationβFuture Enhancement
Section titled βFuture Enhancementβ# Export tokens from Figma (using Tokens Studio plugin)# β packages/theme/figma-tokens.json
# Transform to TypeScriptnode scripts/generate-design-tokens.mjs
# Result: packages/theme/src/tokens.ts updated automaticallyThis enables true design-to-code synchronization.
Common Questions
Section titled βCommon QuestionsβQ: What if I need app-specific colors that arenβt in the theme?
A: Override in the appβs tailwind config:
module.exports = { presets: [createBrandPreset('pinkguest')], theme: { extend: { colors: { 'custom-accent': '#ff69b4', // App-specific }, }, },};Q: Do web and mobile share the EXACT same components?
A: No, but they share design tokens (colors, spacing, etc.). Components are platform-specific but visually consistent.
Q: Can I have different tokens for web vs mobile?
A: Yes, but discouraged. Better to have responsive design with shared tokens.
Q: How do I preview changes before committing?
A: Use Storybook! It shows all components with current tokens.
Related Documentation
Section titled βRelated DocumentationβSummary
Section titled βSummaryβYes, you CAN change design in one place and have it apply to web and mobile!
- One file to rule them all:
packages/theme/src/tokens.ts - Brand overrides:
packages/theme/src/brands.ts - Automatic propagation: Tailwind preset + NativeWind
- Works everywhere: Web, mobile, Storybook
Example workflow:
- Designer updates brand colors in Figma
- Developer updates
packages/theme/src/tokens.ts(or automates it) - All apps get new colors automatically
- No component changes needed (they use
className="bg-primary-500")
This is the power of design tokens!