Building and Publishing Design Systems | Part 2

Learn how to build and publish design systems effectively. Discover best practices for creating reusable components and enhancing UI consistency.

This blogpost is a part of the "Building Design System and Micro Frontends" series. For more content, read the first post. The source code for all parts of this series can be found in this GitHub repository.

For building our design system, we will use react, tailwind, storybook and webpack.

The blogposts of this series
1. Building design system and micro frontends
2. Building and publishing a design system (you are here)
3. Building micro frontends consuming a design system
4. Building a shell application for micro frontends

 

A few words why I selected these technologies

  • React
    Proven, stable, excellent component composition system, focus on back-compatibility. Read the "Design Principles" post on reacts blog; this post outlines react development guiding principles.
     

  • Tailwind
    Gives us a simple way to define seed for the design system. Sizes/Distances scale, colour palettes, shadows, responsive breakpoints, transitions and animations etc., all can be defined succinctly. It also gives us ultimate style isolation and a big productivity boost.
     

  • Storybook
    Helps us develop components in isolation. Helps in component testing and, when exported, delivers portable documentation.
     

  • Webpack
    Proven, stable, vivid plugin ecosystem; a lot of materials.

Setting up a Design System Project

Create directory design-system and run the following commands from it:

npm init -y will setup package.json file.

Run npm run storybook to build and run storybook. It should bind to port 6006. Open http://localhost:6006. You should see some example stories.

The npx sb init command takes care of setting up the storybook. It will create a stories directory with examples in the project root directory. You can remove its content. We will create a simple story later from scratch.

 

Settin up Tailwind

npm i -D tailwindcss@2.2.4  postcss@8.3.5
npx tailwindcss init

npx tailwindcss init will create ./tailwind.config.js file with the default configuration.

Open ./tailwind.config.js Add mode property and set purge patterns (lines 2,3).

module.exports = {
  mode: "jit",
  purge: ["./src/**/*.js", "./src/**/*.html"],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: 
  ,
  variants: {
    extend: 
  ,
  plugins: [],
}

Create ./postcss.config.js in root directory.

Paste following code in ./postcss.config.js:

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {}
  
}

This configuration file adds tailwindcss and autoprefixer plugins to PostCss processing pipeline.

 

Setting up Tailwind for Storybook

In the next two steps we will set up tailwind for storybook. We need to install appropriate plugin and configure it.

Install @storybook/addon-postcss addon for storybook.

npm i -D @storybook/addon-postcss@2.0.0

Update ./.storybook/main.js; add highlighted configuration to addons array:

module.exports = {
  stories: [
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)",
  ],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    {
      name: "@storybook/addon-postcss",
      options: {
        postcssLoaderOptions: {
          implementation: require("postcss"),
        },
      },
    }
  ],
  core: {
    builder: "webpack5",
  },
};

Create file ./src/styles.css.

Paste following code in ./src/styles.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Open ./.storybook/preview.js and add import styles (line 1).

import '../src/styles.css'

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
}

Create Component and Story

Create Button.js file in ./src/components with the following content

import React from "react";

export default function Button({label, disabled, children}) {
  return (
    
  );
}

In ./stories directory create `Button.stories.js` file with the following content:

import React from 'react';

import Button from '../src/components/Button';

export default {
    title: 'Example/Button',
    component: Button,
    argTypes: {
        label: {control: 'text'},
        disabled: {control: 'boolean'}
    },
};

const Template = (args) => 

Run npm run storybook. Open http://localhost:6006. You should see something like this:

Building Design System Package

It is time to create production build of our design system. It should contain only necessary code. We will exclude react from the build. The assumption here is that whoever is consuming design system will be responsible for including react.

In a real project design system should be packaged and published to a npm repository so the other project can use npm to get it. However, for this walkthrough, we will build it and keep it in a directory on the disk. Other projects that we build in the next post will consume it from the disk.

Create an entry point for our library; Create ./src/index.js and add the following content:

import './styles.css'
import Button from "./components/Button";

export   

Every component in our design system must be imported and re-exported in this file.

Install following packages:

npm i -D webpack@5.38.1 webpack-cli@4.7.2  @babel/preset-env@7.14.4 @babel/preset-react@7.13.13 babel-loader@8.2.2 cross-env@7.0.3 css-loader@5.2.6 mini-css-extract-plugin@2.1.0 css-minimizer-webpack-plugin@3.0.2 postcss-loader@5.3.0 style-loader@2.0.0

Create file ./.babelrc with the following content:

{
  presets: [
    [
      '@babel/preset-env',
      {
        modules: false
      }
    ],
    '@babel/preset-react'
  ],
  plugins: []
}

Create file ./webpack.config.js with the following content:

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const config = {
  entry: [
    './src/index.js'
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    library: {
      name: "fitness",
      type: "umd"
    }
  },
  externals: {
    "react": "react",
    "react-dom": "react-dom"
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'
        ]
      }
    ]
  },
  resolve: {
    extensions: [
      '.js',
      '.jsx',
      '.css'
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css'
    })
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin()
    ]
  }
};

module.exports = (env, argv) => {
  config.output.filename = '[name].js';
  return config;
};

There is a lot of things going on in this file; so lets break it out:

  • Line 6 - we define an entry point for our library, all components exported in this file will be available for consumers.

  • Line 9 - the output of the build will be saved to dist folder

  • Lines 11-14 - we configure webpack to create a library and use UMD for modules.

  • Lines 16-19 - we externalize react. This way it is not packaged with the library.

  • Lines 20-41 - standard configuration for building js, jsx and CSS

  • Lines 42-46 - add plugin for CSS extractions

  • Lines 47-52 - configure CSS minification

 

The last step is to add npm script; add following line to package.json scripts array:

"build-design-system": "cross-env NODE_ENV=production webpack --mode production"

To build the design system run npm run build-design-system.

There should be two files in the dist directory. main.js (5KB), and main.css (7KB).

Blog 7/15/21

Building a micro frontend consuming a design system | Part 3

In this blopgpost, you will learn how to create a react application that consumes a design system.

Blog 7/16/21

Building A Shell Application for Micro Frontends | Part 4

We already have a design system, several micro frontends consuming this design system, and now we need a shell application that imports micro frontends and displays them.

Blog 7/13/21

Composite UI with Design System and Micro Frontends

Discover how to create scalable composite UIs using design systems and micro-frontends. Enhance consistency and agility in your development process.

Blog 6/16/23

CSS :has() & Responsive Design

In my journey to tackle a responsive layout problem, I stumbled upon the remarkable benefits of the :has() pseudo-class. Initially, I attempted various other methods to resolve the issue, but ultimately, embracing the power of :has() proved to be the optimal solution. This blog explores my experience and highlights the advantages of utilizing the :has() pseudo-class in achieving flexible layouts.

Blog 11/15/22

5 lessons from running a (remote) design systems book club

Last year I gifted a design systems book I had been reading to a friend and she suggested starting a mini book club so that she’d have some accountability to finish reading the book. I took her up on the offer and so in late spring, our design systems book club was born. But how can you make the meetings fun and engaging even though you're physically separated? Here are a couple of things I learned from running my very first remote book club with my friend!

Blog 10/6/21

Designing and Running a Workshop series: An outline

Learn how to design and execute impactful workshops. Discover tips, strategies, and a step-by-step outline for a successful workshop series.

Blog

Responsible AI: A Guide to Ethical AI Development

Responsible AI is a key requirement in the development and use of AI technologies. You can find everything you need to know here!

Blog 9/17/21

How to gather data from Miro

Learn how to gather data from Miro boards with this step-by-step guide. Streamline your data collection for deeper insights.

Blog 4/28/23

Creating a Social Media Posts Generator Website with ChatGPT

Using the GPT-3-turbo and DALL-E models in Node.js to create a social post generator for a fictional product can be really helpful. The author uses ChatGPT to create an API that utilizes the openai library for Node.js., a Vue component with an input for the title and message of the post. This article provides step-by-step instructions for setting up the project and includes links to the code repository.

Header zu Fullstack Development
Service

Fullstack Development

The trend in Software Development is towards Full-Stack Development. Full-stack developers are programmers who work in both frontend and backend development and thus have competencies in the areas of databases, servers, systems and clients.

Blog 11/12/20

Announcing Domain-Driven Design Exercises

Interested in Domain Driven Design? Then this DDD exercise is perfect for you!

Blog 6/24/21

Using a Skill/Will matrix for personal career development

Discover how a Skill/Will Matrix helps employees identify strengths and areas for growth, boosting personal and professional development.

Blog 7/22/24

Let's build an Enterprise AI Assistant

In the previous blog post we have talked about basic principles of building AI assistants. Let’s take them for a spin with a product case that we’ve worked on: using AI to support enterprise sales pipelines.

Blog 7/22/24

So You are Building an AI Assistant?

So you are building an AI assistant for the business? This is a popular topic in the companies these days. Everybody seems to be doing that. While running AI Research in the last months, I have discovered that many companies in the USA and Europe are building some sort of AI assistant these days, mostly around enterprise workflow automation and knowledge bases. There are common patterns in how such projects work most of the time. So let me tell you a story...

Blog 9/27/22

Creating solutions and projects in VS code

In this post we are going to create a new Solution containing an F# console project and a test project using the dotnet CLI in Visual Studio Code.

Blog 9/7/20

Innovation Incubator Round 1

Team experiments with new technologies and collaborative problem-solving: This was our first round of the Innovation Incubator.

Blog

Crisis management & building a sustainable future with AI

Non-profit organizations develop AI models to tackle global challenges - and draw lessons for businesses worldwide

Blog 2/21/22

The Power of Event Sourcing

This is how we used Event Sourcing to maintain flexibility, handle changes, and ensure efficient error resolution in application development.

Blog 10/7/21

Designing and Running a Workshop series: The board

In this part, we discuss the basic design of the Miro board, which will aid in conducting the workshops.

News 3/30/23

TIMETOACT is Mendix training partner

We are convinced of Mendix's no-code/low-code platforms and are therefore not only a Mendix partner, but also a Mendix training partner.

Bleiben Sie mit dem TIMETOACT GROUP Newsletter auf dem Laufenden!