Skip to content

Design Token System - Single Source of Truth

Status: βœ… Complete
Date: October 11, 2025
Branch: feat/tailwind-integration

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:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 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) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

File: packages/theme/src/tokens.ts

// This is your SINGLE SOURCE OF TRUTH
export 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' },
},
};

File: packages/theme/src/brands.ts

// Pinkguest overrides ONLY the primary color
export const pinkguestTheme = createBrandTheme({
colors: {
primary: {
50: '#fdf2f8',
500: '#ec4899', // Pink instead of blue!
900: '#831843',
},
},
});
// Everything else (typography, spacing, etc.) inherits from base

File: packages/config/tailwind-preset.js

// Import design tokens
const 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
},
},
};

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}'],
};

Scenario: You want to change the primary color for ALL apps.

Solution: Edit ONE file:

packages/theme/src/tokens.ts
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.


Scenario: You want Pinkguest to have a different shade of pink.

Solution: Edit ONE file:

packages/theme/src/brands.ts
export const pinkguestTheme = createBrandTheme({
colors: {
primary: {
500: '#db2777', // Darker pink
},
},
});

Result: Only Pinkguest apps change. All other apps unaffected.


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}'],
};

Scenario: Design wants to switch from Inter to Poppins.

Solution: Edit ONE file:

packages/theme/src/tokens.ts
export const typography = {
families: {
sans: ['Poppins', 'system-ui', 'sans-serif'], // Changed!
},
};

Result: All apps (web and mobile) now use Poppins.


Scenario: Design wants tighter spacing across all apps.

Solution: Edit ONE file:

packages/theme/src/tokens.ts
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.

// Automatically uses design tokens via Tailwind
function Button() {
return (
<button className="bg-primary-500 text-white px-4 py-2 rounded-lg">
Click Me
</button>
);
}
// 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>
);
}
// You can also import tokens directly
import { colors } from '@cloudalt-frontend/theme';
const styles = {
backgroundColor: colors.primary[500],
};
Terminal window
# Edit the tokens file
code packages/theme/src/tokens.ts

No rebuild needed! The tokens are imported at build time.

Terminal window
# Launch Storybook to see all components with new tokens
yarn nx run storybook:storybook
Terminal window
# Clear Metro cache to pick up changes
yarn nx run pinkguest-mobile:start --clear
  • βœ… Design tokens defined in packages/theme
  • βœ… Tailwind preset consumes tokens
  • βœ… Brand-specific overrides system
  • βœ… Documentation complete
  • πŸ“… Add tailwind.config.js to Pinkguest mobile
  • πŸ“… Convert components to use Tailwind classes
  • πŸ“… Test thoroughly
  • πŸ“… Move common components to packages/ui
  • πŸ“… Components already use design tokens via Tailwind
  • πŸ“… Reusable across all brands
  • πŸ“… Copy tailwind config to each app
  • πŸ“… Use brand-specific preset per app
  • πŸ“… Gradual migration of components

Change design tokens once, all apps update automatically.

Each brand can override specific tokens while keeping shared values.

TypeScript types ensure tokens are used correctly.

Same tokens work in:

  • Web apps (Tailwind CSS)
  • Mobile apps (NativeWind)
  • Storybook (design documentation)
  • Direct imports (when needed)

Export tokens from Figma β†’ Update tokens.ts β†’ All apps updated.

Terminal window
# Export tokens from Figma (using Tokens Studio plugin)
# β†’ packages/theme/figma-tokens.json
# Transform to TypeScript
node scripts/generate-design-tokens.mjs
# Result: packages/theme/src/tokens.ts updated automatically

This enables true design-to-code synchronization.

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.

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:

  1. Designer updates brand colors in Figma
  2. Developer updates packages/theme/src/tokens.ts (or automates it)
  3. All apps get new colors automatically
  4. No component changes needed (they use className="bg-primary-500")

This is the power of design tokens!