Post Image

Managing Global Styles in React with Design Tokens

By Andrew Martin on 1st December, 2025

    Design tokens simplify managing styles in React by centralizing visual properties like colors, fonts, and spacing. Instead of hardcoding values across your app, you define reusable tokens (e.g., primary: '#4A00FF') that automatically update everywhere when changed. This approach ensures consistency, speeds up design updates, and supports features like theming (light/dark mode) and multi-platform compatibility.

    Key Benefits:

    • Centralized Styling: Tokens act as a single source of truth.
    • Dynamic Theming: Easily switch between themes (e.g., light/dark mode).
    • Flexibility Across Platforms: Convert tokens into CSS variables, React themes, or platform-specific formats (iOS, Android).
    • Improved Collaboration: Tokens create a shared language between designers and developers.
    • Scalable Design Systems: Use primitive tokens (raw values) and semantic tokens (context-aware) for better organization.

    Quick Steps to Get Started:

    1. Define Tokens: Store values in JSON/YAML (e.g., colors, spacing, typography).
    2. Use Tools: Tools like Style Dictionary transform tokens into CSS variables or other formats.
    3. Integrate with React: Apply CSS variables in components using inline styles, CSS modules, or libraries like styled-components.
    4. Enable Theming: Create separate token sets for light/dark modes and switch dynamically.

    By adopting design tokens, you ensure consistent styling, reduce maintenance overhead, and make your React project more efficient.

    Composable theming with React and design tokens: Consistency and control across apps

    Setting Up a Design Token System

    Laying the groundwork for a design token system involves breaking the process into clear, manageable steps that can grow with your team’s needs.

    Defining and Structuring Design Tokens

    The first step is deciding how to store your design tokens. JSON and YAML are popular options because they’re easy to edit and work across platforms. These formats allow you to organize tokens in a hierarchical structure that aligns with your team’s workflow.

    Here’s an example of a simple JSON structure:

    {   "color": {     "primary": {       "value": "#007bff"     },     "secondary": {       "value": "#6c757d"     }   },   "spacing": {     "small": {       "value": "8px"     },     "medium": {       "value": "16px"     }   },   "typography": {     "fontSize": {       "base": {         "value": "16px"       }     }   } } 

    Each token uses a consistent value property, making it easier to transform and manage. Establishing a clear naming system is just as important. A good naming convention should provide context and scalability. For instance, instead of naming a token simply blue, you could use a descriptive name like wm-material-button-background-primary-on-hover. This approach ensures clarity about the token’s purpose and usage.

    To maintain organization, group tokens into categories like color, spacing, and typography. This separation not only reduces complexity but also allows you to apply different modes – such as light or dark themes – to specific groups of tokens as needed.

    Finally, it’s crucial to distinguish between primitive tokens and semantic tokens for better system management.

    Primitive vs. Semantic Tokens

    Understanding the difference between primitive and semantic tokens helps create a flexible and scalable design system.

    • Primitive tokens are the raw, foundational values. Think of them as the building blocks of your system – specific values like a hex code (#3366FF) or a pixel measurement (16px). Examples include:
      • color.blue.500: #3366FF
      • spacing.scale.4: 16px
    • Semantic tokens (or alias tokens) are context-aware and reference primitive tokens. Instead of directly using color.blue.500, you might define a semantic token like color.primary or button.background. This abstraction allows you to make changes to a single semantic token and have those updates automatically cascade across all components that use it. Semantic tokens also improve collaboration by focusing on design intent rather than raw values.

    For example, updating color.primary in one place would instantly update all buttons, headers, or other elements referencing it. This layered approach ensures your system remains easy to maintain as it evolves.

    Once you’ve defined your tokens, the next step is to implement them using transformation tools.

    Tools for Managing Design Tokens

    Managing tokens manually across platforms isn’t practical, especially as your project grows. That’s where transformation tools come in. These tools take your centralized token definitions and generate platform-specific outputs automatically.

    One popular option is Style Dictionary, which converts tokens stored in JSON or YAML into formats like CSS, Sass, iOS, Android, or React. For React projects, Style Dictionary often outputs CSS custom properties applied at the :root level:

    :root {   --color-primary: #3366FF;   --color-text: var(--color-primary);   --button-background: var(--color-primary);   --button-text: var(--color-text); } 

    Another tool, Knapsack, helps manage tokens and export them into usable formats while maintaining consistent naming conventions. These tools also handle the complexities of scaling your design system, offering configuration options to customize output without needing to write custom code.

    Using Design Tokens with React and CSS Variables

    Design tokens become incredibly powerful when paired with React and CSS variables. By linking tokens to your components via CSS variables, you gain flexibility and dynamic theming options that static values simply can’t offer.

    Converting Tokens to CSS Variables

    The transformation of design tokens into CSS variables happens during your build process. Tools like Style Dictionary can take your JSON token definitions and turn them into CSS custom properties, ready for use in your app.

    Start by creating a centralized stylesheet (e.g., tokens.css or design-tokens.css) where these variables are defined at the :root level. Here’s an example of what the output might look like:

    :root {   --color-blue-500: #3366FF;   --color-primary: var(--color-blue-500);   --color-error: #dc3545;   --spacing-md: 16px;   --font-size-base: 16px;   --button-background-primary-hover: #0056b3; } 

    With this setup, updating a primitive value will automatically cascade changes to any tokens that reference it.

    When naming your tokens, use a clear and consistent system. A simple format like --[category]-[concept]-[variant] works well, yielding names such as --color-primary-default or --spacing-md. For more complex projects, you might adopt a detailed structure like PatternFly‘s --pf-t--[scope]--[component]--[property]--[concept]--[variant]--[state]. Choose a naming convention that suits your team’s workflow and project scale.

    Once your token file is ready, import it into your main stylesheet – usually index.css or App.css.

    Using CSS Variables in React Components

    With tokens defined as CSS variables, you can use them in React components through a few different approaches, depending on your styling strategy.

    Inline styles are great for dynamic values that depend on props or state. Just reference your tokens directly in the style prop:

    <div style={{    background: 'var(--color-primary)',    padding: 'var(--spacing-md)'  }}>   Primary content </div> 

    CSS modules or external stylesheets are ideal for static styles. Define your styles in a separate CSS file and apply them to your components:

    .button {   background: var(--color-primary);   padding: var(--spacing-md);   font-size: var(--font-size-base); }  .button:hover {   background: var(--button-background-primary-hover); } 
    import styles from './Button.module.css';  function Button({ children }) {   return <button className={styles.button}>{children}</button>; } 

    CSS-in-JS libraries like styled-components or React-JSS let you use CSS variables while keeping styles encapsulated within your components. Here’s an example with styled-components:

    import styled from 'styled-components';  const Button = styled.button`   background: var(--color-primary);   padding: var(--spacing-md);   font-size: var(--font-size-base);    &:hover {     background: var(--button-background-primary-hover);   } `; 

    For most projects, the best approach combines external CSS files for token definitions with CSS modules or styled-components for component-specific styling. This keeps your code organized and ensures consistency across your app.

    Setting Up Dynamic Theming with Tokens

    To enable dynamic theming, define separate token sets for each theme and switch between them. This allows you to transform your app’s appearance without modifying individual components.

    Start by creating theme-specific token files. For example, a light-theme.css might look like this:

    .light-theme {   --color-background: #ffffff;   --color-text: #000000;   --color-surface: #f5f5f5;   --color-border: #e0e0e0; } 

    And a dark-theme.css might look like this:

    .dark-theme {   --color-background: #1a1a1a;   --color-text: #ffffff;   --color-surface: #2d2d2d;   --color-border: #404040; } 

    In your React app, use a state management solution or context provider to track the current theme. Then, apply the appropriate class to the document.documentElement or a top-level container:

    function App() {   const [theme, setTheme] = useState('light');    useEffect(() => {     document.documentElement.className = `${theme}-theme`;   }, [theme]);    return (     <div>       <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>         Toggle Theme       </button>       {/* Your app content */}     </div>   ); } 

    When the theme class changes, all components referencing tokens like var(--color-background) will instantly reflect the new theme. This method leverages CSS’s cascade and specificity for efficient theme switching.

    To handle edge cases, use fallback values in your styles: background: var(--color-background, #ffffff). This ensures your app remains functional even if a variable isn’t defined.

    Beyond light and dark modes, you can create themes for different brands, accessibility needs, or user preferences. The key is to keep token names consistent across themes while varying the values. This way, your components remain independent of any specific theme, and adding new themes is as simple as defining new token sets.

    Synchronizing Design Tokens Across Tools and Teams

    Design tokens lose their effectiveness when they exist in isolation. If token values differ between design tools and code, their potential is wasted. By building on the dynamic theming setup mentioned earlier, synchronizing design and development environments transforms design tokens from a theoretical concept into a practical, scalable system.

    Connecting Design Tokens with Design Tools

    The divide between design and development has long been a source of frustration. Designers craft mockups with specific colors, spacing, and typography, only for developers to manually translate those decisions into code. This handoff process often leads to errors, inconsistencies, and wasted effort.

    Modern design tools have stepped in to close this gap by incorporating code-backed components. When your design tool uses the same React components as your developers, both teams operate from a shared foundation, ensuring design tokens stay synchronized.

    For instance, UXPin allows teams to integrate custom Git component repositories directly into the design workflow. Designers can prototype with actual coded components from the repository, meaning they’re working with the design tokens embedded in those components. Since the tokens are part of the codebase, updates sync automatically whenever developers push changes to Git.

    Brian Demchak, Sr. UX Designer at AAA Digital & Creative Services, shared his team’s experience: "As a full stack design team, UXPin Merge is our primary tool when designing user experiences. We have fully integrated our custom-built React Design System and can design with our coded components. It has increased our productivity, quality, and consistency, streamlining our testing of layouts and the developer handoff process."

    For teams using traditional design tools that lack support for code-backed components, synchronization becomes more manual. Typically, this involves exporting tokens from the design tool (often as JSON), then transforming them using tools like Style Dictionary to create CSS variables for React applications. While effective, this approach requires strict processes to avoid drift between design and development.

    This type of integration lays the groundwork for a fully automated workflow, which we’ll explore in the next section.

    Automating Token Updates Across Environments

    Once design-to-code integration is in place, automating token updates ensures consistency across all environments. As your design system grows and your team expands, manual updates simply can’t keep up.

    Start by centralizing your token definitions in a single JSON or YAML file stored in version control. This file acts as the single source of truth. Any token changes are made here first, and updates flow from this central definition to all other environments.

    Set up your build pipeline to handle transformations automatically. When someone commits a token change to the repository, your continuous integration (CI) system should generate platform-specific files, run tests to catch any breaking changes, and deploy updates to your staging environment. This eliminates human error and ensures consistency across the board.

    Larry Sawyer, Lead UX Designer, highlighted the benefits of automation: "When I used UXPin Merge, our engineering time was reduced by around 50%. Imagine how much money that saves across an enterprise-level organization with dozens of designers and hundreds of engineers."

    Consistency in naming conventions is key. A token named color.primary in your JSON file should translate to --color-primary in CSS, tokens.colors.primary in JavaScript, and follow similar patterns across other platforms.

    Building a Collaborative Workflow

    Technology alone can’t guarantee synchronization – you also need processes that keep teams aligned. Design token updates should follow the same review and approval workflows as code changes.

    Manage your token repository using standard version control practices. Use feature branches, peer reviews, and semantic versioning to maintain order. For example, apply major version updates for breaking changes (like removing a token), minor versions for introducing new tokens, and patch versions for small value adjustments. This allows teams to manage dependencies and coordinate updates effectively.

    Document tokens in a registry that includes names, values, and examples of how they’re used. Visual aids like color swatches, typography samples, and spacing scales can help team members quickly understand the purpose of each token. Whenever possible, automate the generation of this documentation directly from your token definitions.

    Establish clear governance for proposing and approving token changes. In smaller teams, this process may be informal. Larger organizations, however, might require a design systems committee to review changes and ensure they align with broader design goals.

    Regular audits are essential for maintaining consistency. Use automated tools to scan your codebase for hardcoded values that should be tokens, unused tokens that can be removed, or tokens that no longer match their definitions. These audits can run as part of your CI pipeline, catching issues before they make it into production.

    The ultimate goal is to create a workflow where token changes are intentional, reviewed, and automatically applied across all environments. By following these practices, you’ll ensure that dynamic theming and token updates work seamlessly across your entire application, supporting the scalable system discussed earlier.

    Best Practices for Scaling Design Token Systems

    Scaling your design token system is essential as your React application grows from a handful of components to hundreds, and your team expands from a small group to multiple squads. What starts as a simple setup can quickly spiral into chaos without proper structure and guidelines.

    Organizing Tokens for Large Applications

    A well-structured token system can save developers hours of frustration. The key is creating a clear hierarchy that mirrors natural design decisions.

    Start by categorizing tokens into functional groups like colors, typography, spacing, sizing, borders, shadows, and animations. Within each group, use a three-layer structure:

    • Primitive tokens: These are raw values, such as --color-base-red: #dc2222.
    • Semantic tokens: Context-aware values that reference primitives, like --color-error: var(--color-base-red).
    • Component-specific tokens: Tokens tailored for specific elements, such as --button-background-primary: var(--color-primary).

    This layered approach balances flexibility with order, ensuring your system can grow without becoming overwhelming.

    Consistency in naming is another cornerstone. Use a predictable pattern that includes a category prefix and describes the token’s purpose. For example:

    • Color tokens: --color-[category]-[shade] (e.g., --color-neutral-300, --color-primary).
    • Typography tokens: --ff-[family] for font families or --fs-[size] for font sizes.
    • Spacing tokens: Descriptive names like --spacing-small, --spacing-medium, and --spacing-large.

    Uniformity across platforms is non-negotiable. A token like color.primary in your JSON file should map directly to --color-primary in CSS and tokens.colors.primary in JavaScript. This consistency reduces confusion and supports automation.

    Tools like Style Dictionary can help by converting tokens into platform-specific formats while preserving your hierarchy. This ensures that your system remains organized, no matter where the tokens are applied.

    Avoiding Common Mistakes

    Scaling a design token system comes with its challenges. Here are some common pitfalls to watch for – and how to sidestep them:

    • Inconsistent naming: A lack of clear naming conventions can make your system impossible to navigate. Set rules upfront, document them thoroughly, and enforce them through code reviews and linting tools.
    • Hardcoding values: When developers bypass tokens and use raw values like #dc2222 directly in CSS, it disconnects components from your token system. Regular audits can help catch and fix these issues.
    • Blurring the line between primitive and semantic tokens: Always use semantic tokens (e.g., --color-error) in components instead of raw values like --color-base-red-500. This keeps your system adaptable.
    • Poor documentation: Without clear guidance, team members may misuse or duplicate tokens. This can lead to unnecessary complexity during updates.
    • Lack of automation: Relying on manual processes like spreadsheets or file copying is a recipe for errors. Invest in tools that streamline token management.
    • No governance: Without a clear process for adding new tokens, your system can become bloated. Establish criteria for when to create new tokens and review additions regularly.

    Atlassian discovered that manual token management doesn’t scale, prompting them to develop automated tools to streamline adoption.

    Addressing these issues early ensures a smoother scaling process.

    Documenting Token Usage

    Good documentation transforms tokens from obscure variables into a shared language for your team. Without it, even the best token system can fall apart.

    Start by creating a token inventory and catalog. Organize tokens by category and include details like names, values, and visual examples. For instance:

    • Color tokens: Show swatches.
    • Typography tokens: Include sample text.
    • Spacing tokens: Use diagrams to illustrate distances.

    Develop a naming convention guide that explains your prefix system and hierarchy, with examples of correct and incorrect usage. This guide should clarify questions like when to create new tokens versus reusing existing ones or how to override tokens for specific components.

    Provide implementation guidelines tailored to different contexts, such as CSS, JavaScript/TypeScript, and design tools. Include concrete examples to help developers integrate tokens seamlessly.

    Explain the token hierarchy – how primitive, semantic, and component-specific tokens relate to each other. Visual diagrams can make these relationships easier to understand.

    For features like dark mode, include theming documentation. Detail how tokens enable theme switching, how to create overrides, and what happens during theme changes.

    In TypeScript projects, helper functions can offer type safety and IntelliSense support, making it easier for developers to find and use tokens without memorizing names.

    Finally, ensure your documentation stays up-to-date and searchable. Tools like Storybook or dedicated design system sites can host this information and sync automatically with token changes. The goal is not just to list tokens but to educate your team on how to use them effectively. With strong documentation, your token system becomes a tool for collaboration, not just a technical detail.

    Conclusion

    Design tokens bring all design choices into one unified system, replacing scattered, hard-coded styles with a consistent, scalable approach.

    The Benefits of Design Tokens in React

    Design tokens do more than just manage styles – they make teamwork smoother and improve efficiency by cutting down on repetitive code and manual updates. A single update to a token ensures that styling stays consistent across the entire system.

    Tokens also simplify the handoff between designers and developers. They act as a shared language, reducing miscommunication and speeding up workflows. As Mark Figueiredo, Sr. UX Team Lead at T. Rowe Price, explained:

    "What used to take days to gather feedback now takes hours. Add in the time we’ve saved from not emailing back-and-forth and manually redlining, and we’ve probably shaved months off timelines."

    When paired with CSS custom properties, design tokens unlock runtime theming without needing code recompilation. This flexibility supports features like dark mode, responsive design, and user personalization.

    Larry Sawyer, Lead UX Designer, shared his experience:

    "When I used UXPin Merge, our engineering time was reduced by around 50%. Imagine how much money that saves across an enterprise-level organization with dozens of designers and hundreds of engineers."

    These advantages set the stage for practical adoption.

    Next Steps

    You don’t need to overhaul everything at once to start using design tokens. Begin small by defining primitive tokens for frequently used values like colors, spacing, and typography. Convert these into CSS variables to gradually integrate them into your components.

    As your system grows, explore tools that connect design and development more seamlessly. For example, UXPin allows teams to work with code-backed components, enabling real-time collaboration between designers and developers while keeping design and production code aligned.

    To ensure long-term success, put clear governance and documentation in place. Define when to create new tokens versus reusing existing ones, use version control to track updates, and maintain detailed usage guidelines. These steps will keep your token system organized and scalable.

    FAQs

    How do design tokens enhance collaboration between designers and developers in React projects?

    Design tokens serve as a bridge between designers and developers, creating a unified system for managing a product’s styles and components. By consolidating design elements like colors, fonts, and spacing into reusable tokens, teams can minimize confusion and make collaboration smoother.

    This method not only makes updates easier but also cuts down on mistakes, helping teams work more quickly while ensuring a consistent and polished user experience.

    What’s the difference between primitive and semantic design tokens, and why does it matter?

    Primitive tokens are the foundation of any design system. These are the raw, reusable values like colors, font sizes, or spacing units. They don’t hint at any specific use; for example, a color token could be named something like primary-100 or neutral-200, with no indication of where or how it should appear in the design.

    Semantic tokens take things a step further by assigning these basic values to specific roles or contexts in your design. For instance, you might have tokens like button-background or header-text-color that clearly define their purpose within the user interface.

    Understanding the difference between primitive and semantic tokens is crucial for keeping your design system organized. Primitive tokens act as the essential building blocks, while semantic tokens bring clarity and consistency by mapping those building blocks to their intended functions in your application.

    How do I use design tokens and CSS variables to enable dynamic theming in a React app?

    To bring dynamic theming to life in a React application, you can combine design tokens and CSS variables for a smooth and efficient solution. Design tokens serve as the central repository for your app’s style properties – like colors, fonts, and spacing – while CSS variables make it easy to apply and manipulate these styles directly in the browser.

    Here’s how it works:

    1. Start by defining your design tokens in a JSON or JavaScript file. These tokens will act as the single source of truth for your app’s visual elements.
    2. Next, map these tokens to CSS variables. You can do this using a global stylesheet or a CSS-in-JS library, depending on your project setup.
    3. To enable dynamic theming, update the CSS variables at runtime. This is typically done by toggling a theme class (e.g., dark-theme or light-theme) on the root element, such as <html> or <body>.

    This method ensures that your app’s styles update instantly when switching themes, without triggering a full re-render. The result? A faster, smoother user experience that feels modern and responsive.

    Related Blog Posts

    Still hungry for the design?

    UXPin is a product design platform used by the best designers on the planet. Let your team easily design, collaborate, and present from low-fidelity wireframes to fully-interactive prototypes.

    Start your free trial

    These e-Books might interest you