Use cases

It's now time to do and try what you've learned in the last chapters. This chapter will guide you to use Specify for two common use cases. The former helps you collect design data from Figma and distribute them to an example web project. The latter helps you do the same with design data defined for light and dark color themes.

Managing design data between Figma and a web project

This use case is for designers and developers who want to synchronize design tokens and assets from Figma and to a web project.

If you keep reading, you'll learn more about:

  1. How to collect design data from Figma
  2. How to store and organize design data in Specify
  3. How to distribute design data in a web project

We will be referring to the following Figma example file:

The designer's part: from Figma to Specify

Please make sure you have already defined in Figma:

  • colors
  • text styles
  • icons

ℹ️ Learn more about how you can collect design data from Figma .

Now, let's collect all your design decisions in Specify:

  1. Connect your Figma account to Specify
  2. Create a Specify repository
  3. Collect your design data by creating a respective source for your colors, text styles and icons

And... that's it 🎉 Your job is done. Now it's time for developers to use your design decisions in their web project.

The developer's part: from Specify to code

Dear developer, it's now time to pull design data from Specify to use it in your web project.

Please make sure you have already:

  1. Created your Specify account
  2. Installed the Specify CLI

The CLI will help you test the configuration we'll be building together in this section.

ℹ️ Want to see a ready-to-use configurations files? Feel free to try our working configurations examples.

Next steps

  1. Open your web project in your favorite IDE
  2. Create a Specify configuration file named .specifyrc.json
  3. Generate a personal access token and copy it

Your configuration file should look like this:

{
  "repository": "@your-organization/your-specify-repository",
  "personalAccessToken": "your-personal-access-token",
  "rules": []
}

ℹ️ Learn more about how to configure Specify in our documentation.

What we will generate

We will be in the shoes of a web developer working with CSS.

We will use the Specify repository we've created in the previous section.

We will organize our design tokens and assets with the following project structure:

🗂 assets
└── 🗂 styles
│   └── colors.css
│   └── fonts.css
│   └── text-styles.css
├── 🗂 fonts
└── 🗂 icons

Colors and text styles will be generated in their respective CSS file. The fonts.css file will contain our font files @import rules. All our font files and icons will be generated in their respective folder.

Pulling colors

Here are colors collected from Figma and stored in our Specify repository:

Colors inside Specify

Here's our final colors.css file:

:root {
  /* COLOR */
  --base-black: hsl(0, 0%, 0%);
  --base-white: hsl(0, 0%, 100%);
  --danger-100: hsl(0, 93%, 94%);
  --danger-200: hsl(0, 96%, 89%);
  --danger-300: hsl(0, 94%, 82%);
  --danger-400: hsl(0, 91%, 71%);
  --danger-50: hsl(0, 86%, 97%);
  --danger-500: hsl(0, 84%, 60%);
  --danger-600: hsl(0, 72%, 51%);
  --danger-700: hsl(0, 74%, 42%);
  --danger-800: hsl(0, 70%, 35%);
  --danger-900: hsl(0, 63%, 31%);
  --informative-100: hsl(214, 95%, 93%);
  --informative-200: hsl(213, 97%, 87%);
  --informative-300: hsl(212, 96%, 78%);
  --informative-400: hsl(213, 94%, 68%);
  --informative-50: hsl(214, 100%, 97%);
  --informative-500: hsl(217, 91%, 60%);
  --informative-600: hsl(221, 83%, 53%);
  --informative-700: hsl(224, 76%, 48%);
  --informative-800: hsl(226, 71%, 40%);
  --informative-900: hsl(224, 64%, 33%);
  --neutral-100: hsl(210, 40%, 96%);
  --neutral-200: hsl(214, 32%, 91%);
  --neutral-300: hsl(213, 27%, 84%);
  --neutral-400: hsl(215, 20%, 65%);
  --neutral-50: hsl(210, 40%, 98%);
  --neutral-500: hsl(215, 16%, 47%);
  --neutral-600: hsl(215, 19%, 35%);
  --neutral-700: hsl(215, 25%, 27%);
  --neutral-800: hsl(217, 33%, 17%);
  --neutral-900: hsl(222, 47%, 11%);
  --primary-100: hsl(251, 91%, 95%);
  --primary-200: hsl(251, 95%, 92%);
  --primary-300: hsl(252, 95%, 85%);
  --primary-400: hsl(255, 92%, 76%);
  --primary-50: hsl(250, 100%, 98%);
  --primary-500: hsl(258, 90%, 66%);
  --primary-600: hsl(262, 83%, 58%);
  --primary-700: hsl(263, 70%, 50%);
  --primary-800: hsl(263, 69%, 42%);
  --primary-900: hsl(264, 67%, 35%);
  --success-100: hsl(141, 84%, 93%);
  --success-200: hsl(141, 79%, 85%);
  --success-300: hsl(142, 77%, 73%);
  --success-400: hsl(142, 69%, 58%);
  --success-50: hsl(138, 76%, 97%);
  --success-500: hsl(142, 71%, 45%);
  --success-600: hsl(142, 76%, 36%);
  --success-700: hsl(142, 72%, 29%);
  --success-800: hsl(143, 64%, 24%);
  --success-900: hsl(144, 61%, 20%);
  --warning-100: hsl(48, 96%, 89%);
  --warning-200: hsl(48, 97%, 77%);
  --warning-300: hsl(46, 97%, 65%);
  --warning-400: hsl(43, 96%, 56%);
  --warning-50: hsl(48, 100%, 96%);
  --warning-500: hsl(38, 92%, 50%);
  --warning-600: hsl(32, 95%, 44%);
  --warning-700: hsl(26, 90%, 37%);
  --warning-800: hsl(23, 83%, 31%);
  --warning-900: hsl(22, 78%, 26%);
}

We want our colors:

  • in a file named colors.css in the following path: assets/styles/
  • in the :root selector
  • as CSS Custom Properties
  • with their name in kebabcase
  • with their value in HSL

Remember that all design tokens coming from Specify are by default returned in JSON. To transform them from JSON to CSS we need to use the to-css-custom-properties parser.

Here's our updated config file:

{
  "repository": "@your-organization/your-specify-repository",
  "personalAccessToken": "your-personal-access-token",
  "rules": [
    {
      "name": "Design Tokens / Colors",
      "path": "assets/styles/colors.css",
      "filter": {
        "types": ["color"]
      },
      "parsers": [
        {
          "name": "to-css-custom-properties",
          "options": {
            "formatTokens": {
              "color": "hsl"
            }
          }
        }
      ]
    }
  ]
}

👉 Test the config for yourself and run: specify pull

Pulling font files

Now, let's pull font files from our Specify repository.

Fonts inside Specify

Fonts inside Specify

Our Specify Specify collected from Figma the following fonts:

  • Inter-Regular
  • Inter-Medium
  • Inter-SemiBold

We want to generate the following folder:

🗂 fonts
  └── Inter-Regular.woff
  └── Inter-Regular.woff2
  └── Inter-Medium.woff
  └── Inter-Medium.woff2
  └── Inter-SemiBold.woff
  └── Inter-SemiBold.woff2

Specify stores all your design data in an agnostic format. Fonts are no different and are stored as .ttf files. We'll use the convert-font parser to convert them to .woff and .woff2 formats.

Let's add in our config file the following rule in the rules array.

...
"rules": [
    ...
    {
    "name": "Assets / Fonts",
    "path": "assets/fonts",
    "filter": {
      "types": ["font"]
    },
    "parsers": [
      {
        "name": "convert-font",
        "options": {
          "formats": ["woff2", "woff"]
        }
      }
    ]
  }
]
...

Now let's import our generated font files in our CSS.

We want a fonts.css file containing our @font-face rules that resembles this:

@font-face {
  font-family: 'Inter-Regular';
  src: url('../fonts/Inter-Regular.woff2') format('woff2'), url('../fonts/Inter-Regular.woff')
      format('woff');
  font-display: swap;
}

@font-face {
  font-family: 'Inter-Medium';
  src: url('../fonts/Inter-Medium.woff2') format('woff2'), url('../fonts/Inter-Medium.woff') format('woff');
  font-display: swap;
}

@font-face {
  font-family: 'Inter-SemiBold';
  src: url('../fonts/Inter-SemiBold.woff2') format('woff2'), url('../fonts/Inter-SemiBold.woff')
      format('woff');
  font-display: swap;
}

Once again, there's a dedicated parser to help you do this: to-css-font-import.

Let's add in our config file the following rule in the rules array:

...
"rules": [
    ...
    {
    "name": "Design Tokens / Fonts",
    "path": "assets/styles/fonts.css",
    "filter": {
      "types": ["font"]
    },
    "parsers": [
      {
        "name": "to-css-font-import",
        "options": {
          "formats": ["woff2", "woff"],
          "includeFontWeight": false,
          "fontsPath": "../fonts/"
        }
      }
    ]
  }
]
...

And now we can finally generate our text styles based on the fonts we previously synchronized.

We want our final text-styles.css file containing text styles as CSS classes to be:

.body-l-text-style {
  font-family: Inter-SemiBold, serif;
  font-weight: 600;
  font-size: 14px;
  line-height: 1.43;
}

.body-m-text-style {
  font-family: Inter-Medium, serif;
  font-weight: 500;
  font-size: 14px;
  line-height: 1.43;
}

.body-s-text-style {
  font-family: Inter-Regular, serif;
  font-weight: 400;
  font-size: 14px;
  line-height: 1.43;
}

.heading-1-text-style {
  font-family: Inter-SemiBold, serif;
  font-weight: 600;
  font-size: 32px;
  line-height: 1.25;
}

.heading-2-text-style {
  font-family: Inter-SemiBold, serif;
  font-weight: 600;
  font-size: 24px;
  line-height: 1.33;
}

.section-text-style {
  font-family: Inter-SemiBold, serif;
  font-weight: 600;
  font-size: 12px;
  line-height: 1.67;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.subtitle-text-style {
  font-family: Inter-Medium, serif;
  font-weight: 500;
  font-size: 18px;
  line-height: 1.78;
}

Notice how our text styles:

  • have a text-style suffix
  • have a relative line-height
  • don't include the CSS color property
  • have a font-family fallback set as serif

The to-css-text-style parser helps you generate your text styles as CSS utility classes.

ℹ️ You can also generate your text styles as SCSS mixins thanks to the to-scss-mixin-text-style parser.

Once again, let's add in our config file the following rule in the rules array:

...
"rules": [
    ...
    {
    "name": "Design Tokens / Text Styles",
    "path": "assets/styles/text-styles.css",
    "filter": {
      "types": ["textStyle"]
    },
    "parsers": [
      {
        "name": "to-css-text-style",
        "options": {
          "exclude": ["color", "text-indent", "vertical-align", "text-align"],
          "suffix": "-text-style",
          "relativeLineHeight": true,
          "genericFamily": "serif"
        }
      }
    ]
  }
]
...

Pulling vectors

Finally, let's pull vectors from our Specify repository.

Vectors inside Specify

Vectors inside Specify

We want our vectors to be pulled as SVG files in an icons folder like so:

🗂 icons
  └── adjustments.svg
  └── archive.svg
  └── arrow-circle-down-outline.svg
  └── arrow-circle-down-solid.svg
    └── ...

Let's add in our config file the following rule in the rules array:

...
"rules": [
    ...
    {
    "name": "Design Tokens / Icons",
    "path": "assets/icons",
    "filter": {
      "types": ["vector"]
    },
    "parsers": [
            {
              "name": "kebabcasify",
              "options": {
                "keys": ["name"]
              }
            },
      {
        "name": "svgo",
        "options": {
          "svgo": {
            "plugins": [
              {
                "removeDimensions": true
              },
              {
                "addAttributesToSVGElement": {
                  "attributes": ["width=\"1em\"", "height=\"1em\""]
                }
              },
              {
                "removeAttrs": {
                  "attrs": "*:(fill|stroke)"
                }
              }
            ]
          }
        }
      },
      {
        "name": "name-assets-files-by-pattern",
        "options": {
          "pattern": "{{name}}.{{format}}"
        }
      }
    ]
  },
]
...

In this rule we have a transformation pipeline composed of 3 parsers:

Let's break this transformation pipeline down 🔎

Some of our vectors have a name containing the following characters: " / " (e.g., arrow-circle-left / Solid). Those characters will make Specify generate the following folder structure:

🗂 arrow-circle-left
  └── Solid.svg

Thus, we kebabcasify our vectors name to have the following result:

🗂 icons
  └── arrow-circle-left-solid.svg
    └── ...

We will do this by applying the kebabcasify parser on each respective vector name property.

The svgo parser helps us automatically optimize our vectors:

  • it replaces their initial width and height by 1em to make our vectors responsive to their parent container's size.
  • it also removes their fill and stroke attributes to help us make the icons take the color of their parent container more easily (e.g., by setting the value of the fill or stroke CSS properties to currentColor).

The name-assets-files-by-pattern parser will help us name our SVG file with a pattern of our choice. Here, we want our SVG file to be named according to their name we previously transformed in kebabcase.

Here's our final config file:

{
  "repository": "@your-organization/your-specify-repository",
  "personalAccessToken": "your-personal-access-token",
  "rules": [
    {
      "name": "Design Tokens / Colors",
      "path": "assets/style/colors.css",
      "filter": {
        "types": ["color"]
      },
      "parsers": [
        {
          "name": "to-css-custom-properties",
          "options": {
            "formatTokens": {
              "color": "hsl"
            }
          }
        }
      ]
    },
    {
      "name": "Assets / Fonts",
      "path": "assets/fonts",
      "filter": {
        "types": ["font"]
      },
      "parsers": [
        {
          "name": "convert-font",
          "options": {
            "formats": ["woff2", "woff"]
          }
        }
      ]
    },
    {
      "name": "Design Tokens / Fonts",
      "path": "assets/style/fonts.css",
      "filter": {
        "types": ["font"]
      },
      "parsers": [
        {
          "name": "to-css-font-import",
          "options": {
            "formats": ["woff2", "woff"],
            "includeFontWeight": false,
            "fontsPath": "../fonts/"
          }
        }
      ]
    },
    {
      "name": "Design Tokens / Text Styles",
      "path": "assets/style/typography.css",
      "filter": {
        "types": ["textStyle"]
      },
      "parsers": [
        {
          "name": "to-css-text-style",
          "options": {
            "exclude": ["color", "text-indent", "vertical-align", "text-align"],
            "suffix": "-text-style",
            "relativeLineHeight": true,
            "genericFamily": "serif"
          }
        }
      ]
    },
    {
      "name": "Design Tokens / Icons",
      "path": "assets/icons",
      "filter": {
        "types": ["vector"]
      },
      "parsers": [
        {
          "name": "kebabcasify",
          "options": {
            "keys": ["name"]
          }
        },
        {
          "name": "svgo",
          "options": {
            "svgo": {
              "plugins": [
                {
                  "removeDimensions": true
                },
                {
                  "removeAttrs": {
                    "attrs": "*:(fill|stroke)"
                  }
                },
                {
                  "addAttributesToSVGElement": {
                    "attributes": ["width=\"1em\"", "height=\"1em\""]
                  }
                }
              ]
            }
          }
        }
      ]
    }
  ]
}

Summary

This use case helped you understand how to synchronize your design tokens and assets from Figma to a web project.

Designers, this use case presented you how to share all your design decisions to developers in a single Specify repository.

Developers, you've been able to get all this design data in your project in CSS. The Specify configuration file you've built helps you automatically get tailored design data for your project.

Managing multiple color themes

This use case will help you setup light and dark color themes between Figma and a web project through Specify.

Introduction

Color themes improve our end users experience. Nowadays, many users expect a UI to support different color themes. However, setting up color themes clearly falls into the "easier said than done" category.

Why? I'm glad you asked. Because after typography, color is what all our UIs are made of. If you care about your users, think through your color contrasts.

If possible, create all your different color theme as soon as possible. The longer you wait, the higher the costs of implementing a new theme will be.

At Specify, we implemented a light and dark theme from day 1.

Previously, color themes used to be created from the same color set. However, this set had to contain (too) many shades to satisfy color contrast requirements of all child themes.

This is why it's now considered a better practice to build your color themes from separate color sets.

To support multiple color themes you must:

  1. Define different color sets in design
  2. Sync those sets between design and code
  3. Make your codebase able to switch from one theme to another

When switching from one color theme to another, your components use the same token names with different values like so:

Light and dark color design tokens applied on a card component.

A color theme is composed of all the design decisions that impact the color of other elements within your UI. Exclude from your color themes all other elements impacted by color.

✅ Color themes include❌ Color themes exclude

Colors

Typography

Gradients

Iconography

Borders

Fonts

Shadows

Measurements

Illustrations

Durations

Depths

ℹ️ Many design decisions remain from one color theme to another: vector shape, text style and components properties. This is why we decided to exclude color from your text styles in Specify.

In short, to support a light and dark color themes, we can structure our design data as is:

GeneralLight ThemeDark Theme

Text style

Color

Color

Measurement

Gradient

Gradient

Vector

Border

Border

Duration

Shadow

Shadow

Depth

Font

This structure helps us compartmentalize all our design data so that if we have to update one of them, we only need to do it in a single place.

The following design data structure will be reflected in:

  1. Figma
  2. Specify
  3. Your codebase

What you will learn

Here's what's on our plate:

  1. Structure Figma files with colors, gradients, borders and shadows
  2. Collect them from Figma and organize them in Specify
  3. Distribute them in a web project

The designer's part: from Figma to Specify

Dear designer, if you're reading this it means you're on the verge of creating your first color themes. Congrats!

As we saw in the introduction, we must organize our design tokens in 3 separate categories:

GeneralLight ThemeDark Theme

Text style

Color

Color

Measurement

Gradient

Gradient

Vector

Border

Border

Duration

Shadow

Shadow

Depth

Font

Creating Figma files

Here are 3 ready to use Figma files you can duplicate to get started:

  1. General
  2. Light Theme
  3. Dark Theme

Now you have your color themes defined in Figma it's time to synchronize them in Specify.

Creating Specify repositories

Once again our three categories will be reflected in Specify.

It means we have to create the following 3 repositories:

  1. General
  2. Light Theme
  3. Dark Theme

We now have to sync from our Figma files all our design decisions in their respective repositories.

ℹ️ Learn more about how to collect design data from Figma.

And that's it! Your job as a designer is done. It's now time for developers to get your design decisions in their codebase.

The developer's part: implementing color themes in code

Dear developer, it's now time to pull from Specify all the design decisions your designers have carefully created.

ℹ️ We will configure Specify to generate a design data architecture to help you manage color themes in your web project.

👉 Have a look at our ready to use Specify configuration examples.

We will be in the shoes of a web developer working with plain CSS files to swap from one color theme to another. Technically speaking we will make our page swap from one set of CSS Custom Properties to another. In this use case, the swap will be made by using a data-theme attribute on the <html> tag. However, feel free to use whatever swapping method suits best your project.

Here's what we want Specify to generate:

🗂 assets
└── 🗂 styles
│   └── 🗂 borders
│   │   └── dark-theme.css
│   │   └── light-theme.css
│   └── 🗂 colors
│   │   └── dark-theme.css
│   │   └── light-theme.css
│   └── 🗂 gradients
│   │   └── dark-theme.css
│   │   └── light-theme.css
│   └── 🗂 shadows
│   │   └── dark-theme.css
│   │   └── light-theme.css
│   ├── depths.css
│   ├── durations.css
│   ├── fonts.css
│   ├── measurements.css
│   └── text-styles.css
├── 🗂 fonts
└── 🗂 icons

Please make sure you have already:

  1. Created your Specify account
  2. Installed the Specify CLI

ℹ️ The CLI will help you test the configuration we'll be building together in this section.

As we saw previously, your Specify repositories will look like this:

GeneralLight ThemeDark Theme

Text style

Color

Color

Measurement

Gradient

Gradient

Vector

Border

Border

Duration

Shadow

Shadow

Depth

Font

Currently, you can't pull design data from several Specify repositories at once. Thus, we need to create 3 different configuration files with each pulling design data from a respective repository.

Specify repositorySpecify configuration file

General

general.json

Light Theme

light-theme.json

Dark Theme

dark-theme.json

Find ready to use versions of those previous configuration files here:

Specifyapp/configurations-examples

Let's break those configuration files down 🔎

The general.json configuration file will generate in your project the following design data:

The light-theme.json configuration files will generate in your project the following design data:

The dark-theme.json configuration files will generate in your project the following design data:

Now, let's test those configurations with the CLI!

  1. Open your terminal
  2. Go to the folder containing your 3 configurations files
  3. Run: specify pull -C general.json; specify pull -C light-theme.json; specify extract -C dark-theme.json;

You should end up with the following structure:

🗂 assets
└── 🗂 styles
│   └── 🗂 borders
│   │   └── dark-theme.css
│   │   └── light-theme.css
│   └── 🗂 colors
│   │   └── dark-theme.css
│   │   └── light-theme.css
│   └── 🗂 gradients
│   │   └── dark-theme.css
│   │   └── light-theme.css
│   └── 🗂 shadows
│   │   └── dark-theme.css
│   │   └── light-theme.css
│   ├── depths.css
│   ├── durations.css
│   ├── fonts.css
│   ├── measurements.css
│   └── text-styles.css
├── 🗂 fonts
└── 🗂 icons

What's next? Well, you need to swap your HTML page from one design tokens set to another. In our case, our tokens are set according to a data-theme attribute value set on the <html> element which is either light or dark.

Our tokens, set as CSS Custom Properties, are defined in one of the following rule:

  • :root[data-theme="light"] {}
  • :root[data-theme="dark"] {}

As a picture is worth a thousand words:

Your swapping method depends on your platform, framework or language you're using. The most important thing to remember is that whatever format you need, you can ask Specify to generate code tailored for your project. Use the Specify API to your advantage and let it do all the heavy lifting.

And that's a wrap 🎬

This swapping method is just an example. Feel free to choose the one that better suits your needs.

Your brand.
Your products.
Always in sync.

Meet the design data platform you ever dreamt of.