<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anna Popova</title>
    <description>The latest articles on DEV Community by Anna Popova (@annwebdotdev).</description>
    <link>https://dev.to/annwebdotdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1034103%2F4166b446-5542-49a4-bf99-10d8506e7e4f.jpeg</url>
      <title>DEV Community: Anna Popova</title>
      <link>https://dev.to/annwebdotdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/annwebdotdev"/>
    <language>en</language>
    <item>
      <title>Unlocking Power of Design Tokens: Practical Steps for Your Next Project</title>
      <dc:creator>Anna Popova</dc:creator>
      <pubDate>Sun, 26 Feb 2023 08:54:58 +0000</pubDate>
      <link>https://dev.to/annwebdotdev/syncing-design-tokens-with-tailwind-css-theme-4d4d</link>
      <guid>https://dev.to/annwebdotdev/syncing-design-tokens-with-tailwind-css-theme-4d4d</guid>
      <description>&lt;p&gt;When our team, consisting of myself as a frontend developer and &lt;a href="https://www.linkedin.com/in/rooman-v/?lipi=urn%3Ali%3Apage%3Ad_flagship3_pulse_read%3B5GQbO7mKRieoTk3Y2sEWGQ%3D%3D" rel="noopener noreferrer"&gt;Roman Vasilev&lt;/a&gt; as a designer, began working on a component library, it became clear that we needed to create an in-house design system based on design tokens. We collaborated to build a tool that met these needs. Throughout the process, we gained valuable insights that we're now eager to share. We hope our experience can help others tackling similar challenges in their projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;At the time of implementation, Figma only had styles, and Figma tokens were not yet available. Since we have a scalable, multi-solution web application distributed around the world, we looked for tools and processes that would help us maintain a single source of truth and synchronize every change instantly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzaly23isxdhfjeojx5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzaly23isxdhfjeojx5o.png" alt="Design tokens flow" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After research, we settled on the following flow that is most convenient for our purposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Figma as source of truth, where all things started.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tokens.studio/" rel="noopener noreferrer"&gt;Tokens Studio&lt;/a&gt; as a Figma plugin that give ability to store, manage, synchronize and update tokens with repositories.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://amzn.github.io/style-dictionary/#/" rel="noopener noreferrer"&gt;Style Dictionary&lt;/a&gt; as tool that allows transform design tokens in any format.&lt;/li&gt;
&lt;li&gt;Tailwind as our CSS framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Design Tokens
&lt;/h3&gt;

&lt;p&gt;Before you start using tokens, you obviously need base styles. We took Tailwind as the core for almost everything except colors. While Tailwind has great palettes, they were too vivid for our brand, especially when applied to charts, and they were difficult to handle with a dark theme. So, we looked at &lt;a href="https://www.radix-ui.com/colors" rel="noopener noreferrer"&gt;Radix UI palettes&lt;/a&gt;, customized them slightly to fit our tokens approach, and created versions for dark mode as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkx5w6xqmid9eubfuvwt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkx5w6xqmid9eubfuvwt.png" alt="Base color palettes" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the base is ready, we need to agree on a naming structure for tokens that is easy to understand for both designers and developers. Naming design tokens might seem like a small detail, but it’s super important.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffj1ijc04xeh42dol5jlj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffj1ijc04xeh42dol5jlj.png" alt="In different environments token names might appear differently" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking at popular Design Systems, we want design token names to explain their purpose and usage, with each part providing specific information while remaining as understandable and short as possible. We arrived at the following naming pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Category&lt;/strong&gt;: Indicates the type of visual design attribute, such as color, spacing, or elevation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Property&lt;/strong&gt;: Specifies the UI element the token applies to, like a border, background, or shadow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context&lt;/strong&gt;: Provides additional context about the token’s role, such as color usage, emphasis, or interaction state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop5656dfxeu8261g4zty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop5656dfxeu8261g4zty.png" alt="Naming structure" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We combined our semantic tokens into the following groups, which indicate property: Primary, Secondary, Typography, Icons, Backgrounds, Surfaces, Borders, Actions, Severity (Success, Error, Warning, Trivial), Translucents, and Accents.&lt;/p&gt;

&lt;p&gt;Each group then has a context that indicates emphasis or interaction, such as: Default, Subtle, Tint, Hover, Active, and Focused.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftre2lmml4fb13mvk8n2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fftre2lmml4fb13mvk8n2.png" alt="List of tokens" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On top of that, we added themes that include light mode, dark mode, and high-contrast mode. Themes can also include non-color elements, such as compact, normal, or wide views, or custom typography styles. This is convenient for customization when a customer buys a white-labeled product.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tokens Synchronization
&lt;/h3&gt;

&lt;p&gt;When you agree on a naming structure and create all styles/variables in Figma, it's time to start syncing them with your codebase repositories. As tool for synchronization with choose &lt;a href="https://tokens.studio/" rel="noopener noreferrer"&gt;Tokens Studio&lt;/a&gt; plugin. This plugin ensures smooth, bidirectional synchronization between design files and code repositories, turning design tokens into a unified source of truth. This helps bridge the gap and enhance collaboration between design and development teams. &lt;a href="https://tokens.studio/" rel="noopener noreferrer"&gt;Tokens Studio&lt;/a&gt; has a supportive community on Slack that is ready to help with any questions, along with well-written documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nk1z0dhf9nqp70wgpam.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nk1z0dhf9nqp70wgpam.png" alt="Plugin Tokens Studio" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where the magic happens. When you need to make changes, just a few clicks, and the updated styles are pulled into the repository, instantly updating everything.&lt;/p&gt;

&lt;p&gt;Now, let's look at this from a developer's perspective!&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up a Next.js project
&lt;/h3&gt;

&lt;p&gt;As a starting point for building a test project, we used a Next.js Typescript template. This boilerplate implements core principles of JAMstack and allows to quickly create serverless applications.&lt;/p&gt;

&lt;p&gt;To set up the project environment, it is necessary to install the following dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// package.json

dependencies: {
  "style-dictionary": "",
  "token-transformer": "",
  "tailwindcss-box-shadow": "", // opt
  "tinycolor2": "", // opt
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, don't forget to regularly update your dependencies to ensure that token modifications are processed correctly.&lt;/p&gt;

&lt;p&gt;The project has a standard file structure. The design tokens are placed within the styles directory. Additionally, the build.js file, which runs Style Dictionary, is located in the scripts folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── styles
│   ├── scripts
│   │   ├── build.js
│   │   └── fns.js
│   ├── tokens
│   │   ├── input
│   │   │   ├── base
│   │   │   │   └── global.json
│   │   │   └── themes
│   │   │       ├── dark
│   │   │       │   └── dark.json
│   │   │       └── light
│   │   │           └── light.json
│   │   └── output
│   │       ├── dark.json
│   │       ├── global.json
│   │       └── light.json
│   ├── dark.css
│   ├── global.css
│   ├── index.css
│   └── light.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automating Design Token updates
&lt;/h3&gt;

&lt;p&gt;The Figma project is synchronized with the repository, and when the designer pushes any changes, that triggers a pipeline, which transforms raw data into CSS variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb95c5j3cba14j82s8mqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb95c5j3cba14j82s8mqh.png" alt="Pushing changes from Token Studio to GitHub" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Design Token files must go through several transformation steps to return valid style sheets. The &lt;a href="https://github.com/tokens-studio/figma-plugin/tree/main/token-transformer" rel="noopener noreferrer"&gt;token-transformer utility&lt;/a&gt; replaces the references with calculated values so that the JSON object conforms to the Style Dictionary standards. The &lt;strong&gt;--expandTypography&lt;/strong&gt; option can be used to convert every font-related property into an individual object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// package.json

"scripts": {
  "transform-tokens-dark": "npx token-transformer app/ui/styles/tokens/input/themes/dark app/ui/styles/tokens/output/dark.json",
  "transform-tokens-global": "npx token-transformer app/ui/styles/tokens/input/base app/ui/styles/tokens/output/global.json --expandTypography",
 "transform-tokens-light": "npx token-transformer app/ui/styles/tokens/input/themes/light app/ui/styles/tokens/output/light.json",
  "transform-tokens": "yarn transform-tokens-light &amp;amp;&amp;amp; yarn transform-tokens-dark &amp;amp;&amp;amp; yarn transform-tokens-global",
  "tokens": "node app/ui/styles/scripts/build.js"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commands in package.json support design token workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Transform design tokens
yarn transform-tokens 

// Build and update CSS variables
yarn tokens 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Global style settings
&lt;/h3&gt;

&lt;p&gt;In &lt;strong&gt;global.json&lt;/strong&gt; file, we've established a foundational set of design variables that are essential across the entire project. This includes crucial aspects like typography, size and z-index.&lt;/p&gt;

&lt;p&gt;Style Dictionary allows us to define functions and then to modify input values. For example, you can specify the letter-spacing property in ems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// build.js

function transformLetterSpacing(value) {
  if (value.endsWith('%')) {
    const percentValue = value.slice(0, -1);
    return `${percentValue / 100}em`;
  }
  return value;
}

StyleDictionaryPackage.registerTransform({
  name: 'size/letterspacing',
  type: 'value',
  transitive: true,
  matcher: (token) =&amp;gt; token.type === 'letterSpacing',
  transformer: (token) =&amp;gt;
  transformLetterSpacing(token.value)
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Theme-specific styles. Dark and Light mode definitions
&lt;/h3&gt;

&lt;p&gt;In dark.json and light.json files, we focus on theme-specific styles, primarily defining colors and shadows tailored for dark and light modes. &lt;/p&gt;

&lt;p&gt;The transform function can combine the number of parameters that define the appearance of a box-shadow into a CSS variable. The resulting value can be used in the theme configuration file after installing the &lt;a href="https://www.npmjs.com/package/tailwindcss-box-shadow" rel="noopener noreferrer"&gt;tailwindcss-box-shadow&lt;/a&gt; plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tailwind.config.js

module.exports = {
  content: ['./app/**/*.{js,ts,jsx,tsx}'],
  darkMode: 'class',
  theme: {},
  plugins: [require('tailwindcss-box-shadow')]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// build.js

StyleDictionaryPackage.registerTransform({
  name: "shadow/css",
  type: "value",
  transitive: true,
  matcher: (token) =&amp;gt; token.type === "boxShadow",
  transformer: (token) =&amp;gt; {
    const shadow = Array.isArray(token.value) ? token.value : [token.value];
    const value = shadow.map((s) =&amp;gt; {
      const { x, y, blur, spread, color } = s;
      return `${x}px ${y}px ${blur}px ${spread}px ${tinycolor(color).toHslString()}`;
    });
    return value.join(", ");
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Color Modifiers
&lt;/h3&gt;

&lt;p&gt;Tokens Studio uses modifiers for fine-tuning color tokens, including lightening, darkening, mixing, and adjusting opacity.&lt;/p&gt;

&lt;p&gt;By creating transformers like color/hslAdjust in Style Dictionary, we can adapt tokens, darkening colors by a specified percentage and returning the result in HSL format. This approach allows for dynamic visual changes in interface elements, for example, darkening the hover token by 27% when the user hovers over it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// light.json

"hover": {
  "value": "{color.blue.500}",
  "type": "color",
  "$extensions": {
  "studio.tokens": {
    "modify": {
      "type": "darken",
      "value": "0.27",
      "space": "hsl"
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// build.js

function resolveTokenValue(token, dictionary) {
  if (
    typeof token.value === 'string' &amp;amp;&amp;amp;
    token.value.startsWith('{') &amp;amp;&amp;amp;
    token.value.endsWith('}')
  ) {
    const resolvedToken = dictionary.getReferences(token.value);
    return resolvedToken ? resolvedToken.value : token.value;
  }
  return token.value;
}

function transformHSL(token, dictionary) {
  const resolvedValue = resolveTokenValue(token, dictionary);
  let color = tinycolor(resolvedValue);
  const modification = token.$extensions?.['studio.tokens']?.modify;
  if (modification &amp;amp;&amp;amp; modification.type === 'darken') {
    color = color.darken(parseFloat(modification.value) * 100);
  }
  return color.toHslString();
}

StyleDictionaryPackage.registerTransform({
  name: 'color/hslDarken',
  type: 'value',
  matcher: (token) =&amp;gt; token.type === 'color' &amp;amp;&amp;amp; token.$extensions,
  transformer: (token, dictionary) =&amp;gt; transformHSL(token, dictionary),
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Theme
&lt;/h3&gt;

&lt;p&gt;Finally, during the building process, a set of CSS variables will be created. Style Dictionary will add selectors to style sheets as a combination of a :root pseudo-class and a themed class. These can be used later to swap from light to dark mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// build.js

files: [
  {
    destination: `${theme}.css`,
    format: 'css/variables',
    selector: `:root.${theme}`
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Tailwind configuration file stores the object that represents the current theme. And Design Tokens can be attached to component styles through CSS variables. Thus, we can update the external presentation of the User Interface by changing the values of the tailwind.config.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tailwind.config.js

theme: {
  colors: {
    primary: {
      DEFAULT: 'var(--color-primary-default)'
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To maintain consistency in UI design, we created a ThemeProvider component and placed it at the top-level of the React tree. That wrapper uses the Context API to pass the current theme data down to child components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// App.tsx

export const App = () =&amp;gt; (
  &amp;lt;ThemeContextWrapper&amp;gt;
    {/* children */}
  &amp;lt;/ThemeContextWrapper&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Creating a Design System based on design tokens using Figma, Tokens Studio, Style Dictionary, and Tailwind has revolutionized our approach to developing component libraries and screen layouts. This method ensures instant synchronization between design and development, significantly enhancing workflow efficiency and reducing implementation time. By maintaining design consistency across all products, our token-based system serves as a robust foundation for both current and future projects. We believe our experience in implementing design tokens can be a game-changer for your next project, enabling you to build a more organized, maintainable, and efficient Design System that seamlessly bridges the gap between design and development.&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>tokensstudio</category>
      <category>designsystem</category>
      <category>colormodifiers</category>
    </item>
  </channel>
</rss>
