Skip to main content

3. Configure Storybook

Overview

We use Storybook for a lot of different useful features it offers. For an overview, have a look at our integrations overview for Storybook.

Install Storybook

We start by initializing Storybook using their CLI. We call it with npx, which runs the command (Storybook) without actually installing the dependency to our project. And as we won't be using their included examples, we just remove those immediately, too:


_2
npx storybook init
_2
rm -rf src/stories

Let's have a look at our package.json, after having added Storybook:

Storybook dependencies

Those are the dependencies added through using npx storybook init. They ensure Storybook itself can be built for development and production.

It also includes Storybooks Essential addon, adding recommended addons by default: https://storybook.js.org/docs/react/essentials/introduction

New scripts entries

Next to the dependencies, two scripts entries were added by the Storybook init:

  1. Storybook: to start your Storybook in development / watch mode
  2. build-storybook: to build a production ready, deployable version of your Storybook
package.json
Copy

_33
{
_33
"name": "@my/design-system",
_33
"version": "1.0.0",
_33
"description": "Design System for all @MY needs",
_33
"main": "dist/index.js",
_33
"scripts": {
_33
"init-tokens": "kickstartDS tokens init",
_33
"build-tokens": "kickstartDS tokens compile",
_33
"test": "echo \"Error: no test specified\" && exit 1",
_33
"storybook": "start-storybook -p 6006",
_33
"build-storybook": "build-storybook"
_33
},
_33
"author": "Jonas Ulrich",
_33
"license": "MIT",
_33
"dependencies": {
_33
"@kickstartds/base": "^2.0.2",
_33
"kickstartds": "^1.0.0",
_33
"react": "^17.0.2",
_33
"react-dom": "^17.0.2"
_33
},
_33
"devDependencies": {
_33
"@babel/core": "^7.19.3",
_33
"@storybook/addon-actions": "^6.5.12",
_33
"@storybook/addon-essentials": "^6.5.12",
_33
"@storybook/addon-interactions": "^6.5.12",
_33
"@storybook/addon-links": "^6.5.12",
_33
"@storybook/builder-webpack4": "^6.5.12",
_33
"@storybook/manager-webpack4": "^6.5.12",
_33
"@storybook/react": "^6.5.12",
_33
"@storybook/testing-library": "^0.0.13",
_33
"babel-loader": "^8.2.5"
_33
}
_33
}

Add the following lines to your .gitignore to exclude locally built versions of Storybook (e.g. by calling yarn build-storybook):

.gitignore
Copy

_8
# Node
_8
node_modules
_8
_8
# Storybook
_8
storybook-static
_8
_8
# kickstartDS
_8
src/token/tokens.css

Configure Storybook

Now that we have installed Storybook, it's time to add some general configuration. We'll also add a first Welcome page to test everything configured so far actually works.

General configuration

For this we'll be looking at the .storybook folder, automatically created for us by npx storybook init. It contains all general configuration to make a Storybook your own, and allows to really adapt it to your use case. We'll set up some integrations that are convenient to use, especially when working with kickstartDS.

The folder contains two files for now:

  • .storybook/main.js
  • .storybook/preview.js

main.js configuration

This file contains configuration for Storybook itself... which addons to load, additional addon configuration, Webpack build & compile configuration, and so on. We'll continue building this up while adding addons in the next steps.

For a detailed overview, have a look at Storybooks documentation.

After npx storybook init

Right after running Storybooks initialization, you should find it looking like this.

.storybook/main.js
Copy

_12
module.exports = {
_12
"stories": [
_12
"../src/**/*.stories.mdx",
_12
"../src/**/*.stories.@(js|jsx|ts|tsx)"
_12
],
_12
"addons": [
_12
"@storybook/addon-links",
_12
"@storybook/addon-essentials",
_12
"@storybook/addon-interactions",
_12
],
_12
"framework": "@storybook/react",
_12
}

Remove quotes

We remove some quotes from main.js, because we're in a .js file.

.storybook/main.js
Copy

_12
module.exports = {
_12
stories: [
_12
"../src/**/*.stories.mdx",
_12
"../src/**/*.stories.@(js|jsx|ts|tsx)"
_12
],
_12
addons: [
_12
"@storybook/addon-links",
_12
"@storybook/addon-essentials",
_12
"@storybook/addon-interactions",
_12
],
_12
framework: "@storybook/react",
_12
}

Deactivate implicit Post CSS loader

As we don't need it, we deactivate the implicit Post CSS loader as recommended.

You can read more about this here.

.storybook/main.js
Copy

_15
module.exports = {
_15
stories: [
_15
"../src/**/*.stories.mdx",
_15
"../src/**/*.stories.@(js|jsx|ts|tsx)"
_15
],
_15
addons: [
_15
"@storybook/addon-links",
_15
"@storybook/addon-essentials",
_15
"@storybook/addon-interactions",
_15
],
_15
framework: "@storybook/react",
_15
features: {
_15
postcss: false,
_15
},
_15
}

Add glob for documentation

We'll be adding a few pages of documentation to test configuration, but these can also serve as the perfect starting point and orientation for your own growing documentation. For Storybook to pick up those pages, we have to tell it where those will be found. We'll be creating that folder docs/ later.

.storybook/main.js
Copy

_16
module.exports = {
_16
stories: [
_16
"../src/**/*.stories.mdx",
_16
"../src/**/*.stories.@(js|jsx|ts|tsx)",
_16
"../docs/**/*.stories.mdx",
_16
],
_16
addons: [
_16
"@storybook/addon-links",
_16
"@storybook/addon-essentials",
_16
"@storybook/addon-interactions",
_16
],
_16
framework: "@storybook/react",
_16
features: {
_16
postcss: false,
_16
},
_16
}

After npx storybook init

Right after running Storybooks initialization, you should find it looking like this.

Remove quotes

We remove some quotes from main.js, because we're in a .js file.

Deactivate implicit Post CSS loader

As we don't need it, we deactivate the implicit Post CSS loader as recommended.

You can read more about this here.

Add glob for documentation

We'll be adding a few pages of documentation to test configuration, but these can also serve as the perfect starting point and orientation for your own growing documentation. For Storybook to pick up those pages, we have to tell it where those will be found. We'll be creating that folder docs/ later.

.storybook/main.js
CopyExpandClose

_12
module.exports = {
_12
"stories": [
_12
"../src/**/*.stories.mdx",
_12
"../src/**/*.stories.@(js|jsx|ts|tsx)"
_12
],
_12
"addons": [
_12
"@storybook/addon-links",
_12
"@storybook/addon-essentials",
_12
"@storybook/addon-interactions",
_12
],
_12
"framework": "@storybook/react",
_12
}

preview.js configuration

This file specifically includes configuration for component previews, we'll need to make sure all needed CSS is loaded here... for example! Additionally, configuration for how stories are displayed can be adjusted globally, through the exports parameters and decorators (amongst others, learn more here).

After npx storybook init

We'll start off again with the file as created by Storybooks initialization.

.storybook/preview.js
Copy

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

Add story sorting

Adding a storySort function to the options allows us to ensure the Welcome page will always be displayed first. Everything else should be sorted alphabetically. Learn more about storySort.

.storybook/preview.js
Copy

_22
export const parameters = {
_22
actions: { argTypesRegex: "^on[A-Z].*" },
_22
controls: {
_22
matchers: {
_22
color: /(background|color)$/i,
_22
date: /Date$/,
_22
},
_22
},
_22
options: {
_22
storySort(a, b) {
_22
// welcome page to top!
_22
if (a[0].includes("welcome")) {
_22
return -1;
_22
}
_22
_22
// alphabetically
_22
return a[1].kind === b[1].kind
_22
? 0
_22
: a[1].id.localeCompare(b[1].id, undefined, { numeric: true });
_22
},
_22
},
_22
}

After npx storybook init

We'll start off again with the file as created by Storybooks initialization.

Add story sorting

Adding a storySort function to the options allows us to ensure the Welcome page will always be displayed first. Everything else should be sorted alphabetically. Learn more about storySort.

.storybook/preview.js
CopyExpandClose

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

Adding a Welcome page

As promised we add a Welcome page now, to verify configuration... and to have something in Storybook to display in the browser.

Create a folder docs at the root of your repository, and add a file welcome.stories.mdx to it. .mdx is an extension of the popular Markdown format, allowing the use of React / JSX components as part of your documentation. In the context of kickstartDS this also means being able to use all of your components as part of your Storybook documentation, too. For example having nice hero images on pages important to you!

Learn more about the .mdx format here.


_2
mkdir -p docs
_2
touch docs/welcome.stories.mdx

Add the following content to it:

Define story title and category

We define a title and category for our Welcome page by importing and using Meta from @storybook/addon-docs, a component provided to us by Storybook.

This would also be a first example on the benefits of using .mdx for documentation.

Some initial dummy content

The rest of the file just contains some dummy content to start. Feel free to replace this with something more meaningful, but you'll probably want to revisit this page later, anyways!

docs/welcome.stories.mdx
Copy

_15
import { Meta } from "@storybook/addon-docs";
_15
_15
<Meta title="Welcome" />
_15
_15
# Your kickstartDS based Design System
_15
_15
Ipsum voluptate reprehenderit ut aliquid laborum enim. Optio et suscipit aliquam voluptate nostrum est. Corrupti ab laboriosam qui aut aliquid iusto nobis voluptatum. Perferendis non reiciendis illum. Vel et sint est.
_15
_15
Alias placeat accusantium voluptatem pariatur dolor et. Dicta quia officia voluptatem quia nulla natus. Accusantium in voluptate porro. Libero voluptatem placeat ipsum dolores deserunt omnis odio.
_15
_15
Sed distinctio consequuntur et et aliquid. Exercitationem autem impedit expedita. Beatae eum voluptatem eaque necessitatibus repellendus. Velit qui est optio. Ut est voluptates incidunt et qui sed dolorem. Quidem molestiae velit non laudantium consequatur autem.
_15
_15
Amet doloremque voluptas suscipit. Omnis incidunt sit nesciunt voluptate sed voluptatem delectus quis. Repudiandae occaecati magni fugit. Minus sunt quia ab temporibus. Voluptatibus vel odit facere enim et.
_15
_15
Consequatur et consequuntur et. Nam consequatur sed voluptas ea. Tempore vero velit et hic. Ut et aspernatur quaerat ut aut consequatur. Quisquam aliquid ea adipisci nulla quia ut dolor. Accusamus earum quasi quaerat.

Verifying configuration

It's not much, yet, but we can start our Storybook now to see our Welcome page in action:


_1
yarn storybook

This should automatically open Storybook in your browser of choice. Next to displaying your first page (🙌), there's something interesting that happened!

As part of the left sidebar, and under your initially opened Welcome page, there'll be a section titled @kickstartds/base. This gets shown because we've added @kickstartds/base as a dependency before. kickstartDS uses Storybook composition to always include the base documentation (in the correct version used by your Design System) to your Storybook, as a handy reference!

Design Token integration

Next up is adding some glue code to have our Design Token set nicely integrated with Storybook. We can start by copying some stories provided by kickstartDS (those are the same that can be seen here).

Add storybook-design-token addon

For Design Token documentation we also use storybook-design-token as an addon. Mainly for its DesignTokenDocBlock component, which helps in rendering the pages we've copied. So we also install that, too:


_2
cp -r node_modules/@kickstartds/core/lib/design-tokens docs/tokens
_2
yarn add -D storybook-design-token

But if you start your Storybook now (yarn storybook), you'll be greeted by empty pages. That's because we've not set up the actual Design Token integration with Storybook / our Style Dictionary, yet.

Integrate with Style Dictionary

As the storybook-design-token addon needs our tokens in a specific format (read more here), we adjust our Style Dictionary configuration in sd.config.js to include the provided Storybook configuration. We also tell it to put those Storybook specific files into our already existing src/token directory:

sd.config.js
Copy

_18
const path = require('path');
_18
const StyleDictionary = require("style-dictionary");
_18
const { config } = require("@kickstartds/style-dictionary");
_18
_18
module.exports = StyleDictionary.extend(config).extend({
_18
source: [
_18
"src/token/dictionary/**/*.json",
_18
path.join(path.dirname(require.resolve('@kickstartds/core/package.json')), 'source/design-tokens/icons/*.svg')
_18
],
_18
platforms: {
_18
css: {
_18
buildPath: 'src/token/'
_18
},
_18
storybook: {
_18
buildPath: 'src/token/storybook/'
_18
},
_18
},
_18
});

With that change, re-build your Design Token set:


_1
yarn build-tokens

You'll notice it now writes two additional files for you, specifically for the Storybook integration:

Annotated tokens.css

Those are all of our Design Token converted to CSS custom properties (as with src/token/tokens.css), but with the correct storybook-design-token presenters already added.

icons.svg icon collection

Contains a collection of all used icons. Similarly to before, they just get annotated with the correct presenters for storybook-design-token for Storybook.
The file gets picked up by the addon automatically, we don't need to add any additional configuration.


_43
yarn run v1.22.18
_43
$ kickstartDS tokens compile
_43
_ _ _ _ _ ____ ____
_43
| | _(_) ___| | _____| |_ __ _ _ __| |_| _ \/ ___|
_43
| |/ / |/ __| |/ / __| __/ _` | '__| __| | | \___ \
_43
| <| | (__| <\__ \ || (_| | | | |_| |_| |___) |
_43
|_|\_\_|\___|_|\_\___/\__\__,_|_| \__|____/|____/
_43
_43
______________/\\\\\\\\\__/\\\______________/\\\\\\\\\\\_______
_43
___________/\\\////////__\/\\\_____________\/////\\\///________
_43
_________/\\\/___________\/\\\_________________\/\\\___________
_43
________/\\\_____________\/\\\_________________\/\\\___________
_43
_______\/\\\_____________\/\\\_________________\/\\\___________
_43
_______\//\\\____________\/\\\_________________\/\\\___________
_43
________\///\\\__________\/\\\_________________\/\\\___________
_43
__/\\\____\////\\\\\\\\\_\/\\\\\\\\\\\\\\\__/\\\\\\\\\\\__/\\\_
_43
_\///________\/////////__\///////////////__\///////////__\///__
_43
_43
Version: 1.0.0
_43
For more information visit:
_43
https://www.kickstartDS.com/docs/intro/cli
_43
_43
Starting...
_43
[kickstartDS: general] [info]: welcome to the kickstartDS CLI
_43
[kickstartDS: tokens/compile] starting: compile command with compile variable compile-task
_43
[1/1] [compile: check] [info]: checking prerequesites before starting
_43
[1/1] [compile: check] [info]: prerequesites met, starting
_43
[compile: cleanup] [info]: cleaning up temp dir /tmp/tokens-compile-compile-task before starting command
_43
[compile: cleanup] [info]: finished cleaning up temp dir /tmp/tokens-compile-compile-task before starting command
_43
[1/1] [compile: compile] [info]: running the compile subtask
_43
[1/1] [compile: compile] [info]: getting Style Dictionary from token files
_43
[1/1] [compile: compile] [info]: compiling Style Dictionary to needed CSS and assets
_43
_43
css
_43
✔︎ src/token/tokens.css
_43
_43
storybook
_43
✔︎ src/token/storybook/tokens.css
_43
✔︎ src/token/storybook/icons.svg
_43
[1/1] [compile: compile] [info]: copying generated CSS and assets to local folder
_43
[1/1] [compile: compile] [info]: finished running the compile subtask successfully
_43
[kickstartDS: tokens/compile] finished: compile command with compile variable compile-task
_43
Done in 1.08s.

Integrate with Storybook manager

The final piece of the puzzle to get our Design Token docs working is to actually load our prepared src/token/storybook/tokens.css file. As this is specific to Storybook (we'll use the untouched, converted CSS custom properties of src/token/tokens.css for preview.js), this will be done in a new file .storybook/manager.scss. We use Sass here, as it will be featured later in this guide for component customization, too.

Here it helps re-using the file in src/token, while also adding some CSS.

Create the file:


_1
touch .storybook/manager.scss

And add the following content to it:

.storybook/manager.scss
Copy

_7
@use '../src/token/storybook/tokens.css';
_7
_7
.sidebar-item {
_7
svg {
_7
color: inherit;
_7
}
_7
}

We pull in our generated tokens with @use, and add some CSS to ensure the icon colors actually get inherited.

Now that we've added a .scss file, we'll need to also add Sass compilation capabilities to our project. Install sass and add the following lines to your package.json:


_1
yarn add -D sass

After adding sass

A single entry in devDependencies should've been added.

package.json
Copy

_35
{
_35
"name": "@my/design-system",
_35
"version": "1.0.0",
_35
"description": "Design System for all @MY needs",
_35
"main": "dist/index.js",
_35
"scripts": {
_35
"init-tokens": "kickstartDS tokens init",
_35
"build-tokens": "kickstartDS tokens compile",
_35
"test": "echo \"Error: no test specified\" && exit 1",
_35
"storybook": "start-storybook -p 6006",
_35
"build-storybook": "build-storybook"
_35
},
_35
"author": "Jonas Ulrich",
_35
"license": "MIT",
_35
"dependencies": {
_35
"@kickstartds/base": "^2.0.2",
_35
"kickstartds": "^1.0.0",
_35
"react": "^17.0.2",
_35
"react-dom": "^17.0.2"
_35
},
_35
"devDependencies": {
_35
"@babel/core": "^7.19.3",
_35
"@storybook/addon-actions": "^6.5.12",
_35
"@storybook/addon-essentials": "^6.5.12",
_35
"@storybook/addon-interactions": "^6.5.12",
_35
"@storybook/addon-links": "^6.5.12",
_35
"@storybook/builder-webpack4": "^6.5.12",
_35
"@storybook/manager-webpack4": "^6.5.12",
_35
"@storybook/react": "^6.5.12",
_35
"@storybook/testing-library": "^0.0.13",
_35
"babel-loader": "^8.2.5",
_35
"sass": "^1.56.0",
_35
"storybook-design-token": "^2.8.0"
_35
}
_35
}

Re-order scripts entries

To keep some order in our scripts entries, we re-order them to be sorted alphabetically before adding some more.

Trailing commas

It's easy to mix up some trailing commas here!

package.json
Copy

_35
{
_35
"name": "@my/design-system",
_35
"version": "1.0.0",
_35
"description": "Design System for all @MY needs",
_35
"main": "dist/index.js",
_35
"scripts": {
_35
"build-storybook": "build-storybook",
_35
"build-tokens": "kickstartDS tokens compile",
_35
"init-tokens": "kickstartDS tokens init",
_35
"storybook": "start-storybook -p 6006",
_35
"test": "echo \"Error: no test specified\" && exit 1"
_35
},
_35
"author": "Jonas Ulrich",
_35
"license": "MIT",
_35
"dependencies": {
_35
"@kickstartds/base": "^2.0.2",
_35
"kickstartds": "^1.0.0",
_35
"react": "^17.0.2",
_35
"react-dom": "^17.0.2"
_35
},
_35
"devDependencies": {
_35
"@babel/core": "^7.19.3",
_35
"@storybook/addon-actions": "^6.5.12",
_35
"@storybook/addon-essentials": "^6.5.12",
_35
"@storybook/addon-interactions": "^6.5.12",
_35
"@storybook/addon-links": "^6.5.12",
_35
"@storybook/builder-webpack4": "^6.5.12",
_35
"@storybook/manager-webpack4": "^6.5.12",
_35
"@storybook/react": "^6.5.12",
_35
"@storybook/testing-library": "^0.0.13",
_35
"babel-loader": "^8.2.5",
_35
"sass": "^1.56.0",
_35
"storybook-design-token": "^2.8.0"
_35
}
_35
}

Compile .storybook/manager.scss

We add a script entry called sass-manager, which when called will compile our Sass to a regular CSS file (placed in static/manager.css) to be read by Storybook.

package.json
Copy

_36
{
_36
"name": "@my/design-system",
_36
"version": "1.0.0",
_36
"description": "Design System for all @MY needs",
_36
"main": "dist/index.js",
_36
"scripts": {
_36
"build-storybook": "build-storybook",
_36
"build-tokens": "kickstartDS tokens compile",
_36
"init-tokens": "kickstartDS tokens init",
_36
"sass-manager": "sass --load-path=node_modules .storybook/manager.scss static/manager.css",
_36
"storybook": "start-storybook -p 6006",
_36
"test": "echo \"Error: no test specified\" && exit 1"
_36
},
_36
"author": "Jonas Ulrich",
_36
"license": "MIT",
_36
"dependencies": {
_36
"@kickstartds/base": "^2.0.2",
_36
"kickstartds": "^1.0.0",
_36
"react": "^17.0.2",
_36
"react-dom": "^17.0.2"
_36
},
_36
"devDependencies": {
_36
"@babel/core": "^7.19.3",
_36
"@storybook/addon-actions": "^6.5.12",
_36
"@storybook/addon-essentials": "^6.5.12",
_36
"@storybook/addon-interactions": "^6.5.12",
_36
"@storybook/addon-links": "^6.5.12",
_36
"@storybook/builder-webpack4": "^6.5.12",
_36
"@storybook/manager-webpack4": "^6.5.12",
_36
"@storybook/react": "^6.5.12",
_36
"@storybook/testing-library": "^0.0.13",
_36
"babel-loader": "^8.2.5",
_36
"sass": "^1.56.0",
_36
"storybook-design-token": "^2.8.0"
_36
}
_36
}

Watch mode for .storybook/manager.scss

And while we're at it, we'll also add a watch task that can be used in development. This rebuilds your changes to manager.scss live, and triggers a reload in your browser subsequently.

package.json
Copy

_37
{
_37
"name": "@my/design-system",
_37
"version": "1.0.0",
_37
"description": "Design System for all @MY needs",
_37
"main": "dist/index.js",
_37
"scripts": {
_37
"build-storybook": "build-storybook",
_37
"build-tokens": "kickstartDS tokens compile",
_37
"init-tokens": "kickstartDS tokens init",
_37
"sass-manager": "sass --load-path=node_modules .storybook/manager.scss static/manager.css",
_37
"storybook": "start-storybook -p 6006",
_37
"test": "echo \"Error: no test specified\" && exit 1",
_37
"watch:sass-manager": "yarn sass-manager --watch"
_37
},
_37
"author": "Jonas Ulrich",
_37
"license": "MIT",
_37
"dependencies": {
_37
"@kickstartds/base": "^2.0.2",
_37
"kickstartds": "^1.0.0",
_37
"react": "^17.0.2",
_37
"react-dom": "^17.0.2"
_37
},
_37
"devDependencies": {
_37
"@babel/core": "^7.19.3",
_37
"@storybook/addon-actions": "^6.5.12",
_37
"@storybook/addon-essentials": "^6.5.12",
_37
"@storybook/addon-interactions": "^6.5.12",
_37
"@storybook/addon-links": "^6.5.12",
_37
"@storybook/builder-webpack4": "^6.5.12",
_37
"@storybook/manager-webpack4": "^6.5.12",
_37
"@storybook/react": "^6.5.12",
_37
"@storybook/testing-library": "^0.0.13",
_37
"babel-loader": "^8.2.5",
_37
"sass": "^1.56.0",
_37
"storybook-design-token": "^2.8.0"
_37
}
_37
}

After adding sass

A single entry in devDependencies should've been added.

Re-order scripts entries

To keep some order in our scripts entries, we re-order them to be sorted alphabetically before adding some more.

Trailing commas

It's easy to mix up some trailing commas here!

Compile .storybook/manager.scss

We add a script entry called sass-manager, which when called will compile our Sass to a regular CSS file (placed in static/manager.css) to be read by Storybook.

Watch mode for .storybook/manager.scss

And while we're at it, we'll also add a watch task that can be used in development. This rebuilds your changes to manager.scss live, and triggers a reload in your browser subsequently.

package.json
CopyExpandClose

_35
{
_35
"name": "@my/design-system",
_35
"version": "1.0.0",
_35
"description": "Design System for all @MY needs",
_35
"main": "dist/index.js",
_35
"scripts": {
_35
"init-tokens": "kickstartDS tokens init",
_35
"build-tokens": "kickstartDS tokens compile",
_35
"test": "echo \"Error: no test specified\" && exit 1",
_35
"storybook": "start-storybook -p 6006",
_35
"build-storybook": "build-storybook"
_35
},
_35
"author": "Jonas Ulrich",
_35
"license": "MIT",
_35
"dependencies": {
_35
"@kickstartds/base": "^2.0.2",
_35
"kickstartds": "^1.0.0",
_35
"react": "^17.0.2",
_35
"react-dom": "^17.0.2"
_35
},
_35
"devDependencies": {
_35
"@babel/core": "^7.19.3",
_35
"@storybook/addon-actions": "^6.5.12",
_35
"@storybook/addon-essentials": "^6.5.12",
_35
"@storybook/addon-interactions": "^6.5.12",
_35
"@storybook/addon-links": "^6.5.12",
_35
"@storybook/builder-webpack4": "^6.5.12",
_35
"@storybook/manager-webpack4": "^6.5.12",
_35
"@storybook/react": "^6.5.12",
_35
"@storybook/testing-library": "^0.0.13",
_35
"babel-loader": "^8.2.5",
_35
"sass": "^1.56.0",
_35
"storybook-design-token": "^2.8.0"
_35
}
_35
}

The correct place to put such CSS specific to Storybooks UI is .storybook/manager-head.html (you can read more about their CSS escape hatches here). We'll create that file, too:


_1
touch .storybook/manager-head.html

And add the following content to it:

.storybook/manager-head.html
Copy

_1
<link rel="stylesheet" href="manager.css" />

Finalizing Design Token integration steps

To get Storybook to pick up our static folder when run / compiled, and thus above relative reference to work, we also need to tell Storybook about it in .storybook/main.js. Further we have to add the storybook-design-token addon to the addons array. The designTokenGlob tells it where to find our token definitions (the annotated token.css from before):

.storybook/main.js
Copy

_21
module.exports = {
_21
stories: [
_21
"../src/**/*.stories.mdx",
_21
"../src/**/*.stories.@(js|jsx|ts|tsx)",
_21
"../docs/**/*.stories.mdx",
_21
],
_21
addons: [
_21
"@storybook/addon-links",
_21
"@storybook/addon-essentials",
_21
"@storybook/addon-interactions",
_21
{
_21
name: "storybook-design-token",
_21
options: { designTokenGlob: "src/token/storybook/*" },
_21
},
_21
],
_21
framework: "@storybook/react",
_21
staticDirs: ["../static"],
_21
features: {
_21
postcss: false,
_21
},
_21
}

Finally, we'll disable the storybook-design-token addon in Canvas views. It's output there is redundant when having explicit pages for Design Token, and tends to be a bit noisy in the context of a singular component, anyway. Learn more about that option (and other ones) in the official addon documentation.

As this is an option concerned with the general rendering of a Story, the change will have to be made in .storybook/preview.js:

.storybook/preview.js
Copy

_25
export const parameters = {
_25
actions: { argTypesRegex: "^on[A-Z].*" },
_25
controls: {
_25
matchers: {
_25
color: /(background|color)$/i,
_25
date: /Date$/,
_25
},
_25
},
_25
options: {
_25
storySort(a, b) {
_25
// welcome page to top!
_25
if (a[0].includes("welcome")) {
_25
return -1;
_25
}
_25
_25
// alphabetically
_25
return a[1].kind === b[1].kind
_25
? 0
_25
: a[1].id.localeCompare(b[1].id, undefined, { numeric: true });
_25
},
_25
},
_25
designToken: {
_25
disable: true,
_25
},
_25
}

If you re-start, or re-open, your Storybook now (yarn storybook), you'll be greeted by all your glorious Design Token. Neatly categorized by category and semantic meaning!

Empty tables in Firefox?

This was a bug with the storybook-design-token addon, see this issue.

This is fixed starting with version 2.8.0 of the addon. If you're affected, just update your version to ^2.8.0 or higher in your package.json, to fix the addon!

We'll add those additional files generated based on our Design Token set to our .gitignore now:

.gitignore
Copy

_11
# Node
_11
node_modules
_11
_11
# Storybook
_11
storybook-static
_11
_11
# kickstartDS
_11
src/token/tokens.css
_11
src/token/storybook/tokens.css
_11
src/token/storybook/icons.svg
_11
static/manager.css

Add Storybook theming

We have a Design Token set, we have a Storybook... what better idea than to combine those two! Re-using our existing token to add some (reserved) theming to our general Storybook UI also serves as a great first, albeit small, demonstration for how useful a well constructed Design Token set can be!

Creating a Storybook theme involves creating two files, and adding a new output format (.js) to our Style Dictionary:

  • .storybook/manager.js: used to import and set our custom theme
  • .storybook/themes.js: definition of our custom theme, using the new output format

Learn more about theming in Storybook.

Adding a Style Dictionary transform

We start off by adding the new Style Dictionary transform in sd.config.js:

sd.config.js
Copy

_28
const path = require('path');
_28
const StyleDictionary = require("style-dictionary");
_28
const { config } = require("@kickstartds/style-dictionary");
_28
_28
module.exports = StyleDictionary.extend(config).extend({
_28
source: [
_28
"src/token/dictionary/**/*.json",
_28
path.join(path.dirname(require.resolve('@kickstartds/core/package.json')), 'source/design-tokens/icons/*.svg')
_28
],
_28
platforms: {
_28
css: {
_28
buildPath: 'src/token/'
_28
},
_28
storybook: {
_28
buildPath: 'src/token/storybook/'
_28
},
_28
js: {
_28
transforms: ["attribute/cti", "name/cti/pascal", "size/rem", "color/css"],
_28
buildPath: "src/token/storybook/",
_28
files: [
_28
{
_28
destination: "tokens.js",
_28
format: "javascript/es6",
_28
},
_28
],
_28
},
_28
},
_28
});

The transforms ensure a naming format that we'll use in our .storybook/themes.js, up next. We also instruct our new transform to put the generate JavaScript file into our Storybook specific token folder src/token/storybook as tokens.js. We opt for JavaScript so an easy import from inside .storybook/themes.js is possible. This is also the reason for selecting javascript/es6 as the format.

With that new transform in place, re-build your Design Token set again:


_1
yarn build-tokens

You'll be greeted by a new file being created at src/token/storybook/tokens.js:


_46
yarn run v1.22.18
_46
$ kickstartDS tokens compile
_46
_ _ _ _ _ ____ ____
_46
| | _(_) ___| | _____| |_ __ _ _ __| |_| _ \/ ___|
_46
| |/ / |/ __| |/ / __| __/ _` | '__| __| | | \___ \
_46
| <| | (__| <\__ \ || (_| | | | |_| |_| |___) |
_46
|_|\_\_|\___|_|\_\___/\__\__,_|_| \__|____/|____/
_46
_46
______________/\\\\\\\\\__/\\\______________/\\\\\\\\\\\_______
_46
___________/\\\////////__\/\\\_____________\/////\\\///________
_46
_________/\\\/___________\/\\\_________________\/\\\___________
_46
________/\\\_____________\/\\\_________________\/\\\___________
_46
_______\/\\\_____________\/\\\_________________\/\\\___________
_46
_______\//\\\____________\/\\\_________________\/\\\___________
_46
________\///\\\__________\/\\\_________________\/\\\___________
_46
__/\\\____\////\\\\\\\\\_\/\\\\\\\\\\\\\\\__/\\\\\\\\\\\__/\\\_
_46
_\///________\/////////__\///////////////__\///////////__\///__
_46
_46
Version: 1.0.0
_46
For more information visit:
_46
https://www.kickstartDS.com/docs/intro/cli
_46
_46
Starting...
_46
[kickstartDS: general] [info]: welcome to the kickstartDS CLI
_46
[kickstartDS: tokens/compile] starting: compile command with compile variable compile-task
_46
[1/1] [compile: check] [info]: checking prerequesites before starting
_46
[1/1] [compile: check] [info]: prerequesites met, starting
_46
[compile: cleanup] [info]: cleaning up temp dir /tmp/tokens-compile-compile-task before starting command
_46
[compile: cleanup] [info]: finished cleaning up temp dir /tmp/tokens-compile-compile-task before starting command
_46
[1/1] [compile: compile] [info]: running the compile subtask
_46
[1/1] [compile: compile] [info]: getting Style Dictionary from token files
_46
[1/1] [compile: compile] [info]: compiling Style Dictionary to needed CSS and assets
_46
_46
css
_46
✔︎ src/token/tokens.css
_46
_46
storybook
_46
✔︎ src/token/storybook/tokens.css
_46
✔︎ src/token/storybook/icons.svg
_46
_46
js
_46
✔︎ src/token/storybook/tokens.js
_46
[1/1] [compile: compile] [info]: copying generated CSS and assets to local folder
_46
[1/1] [compile: compile] [info]: finished running the compile subtask successfully
_46
[kickstartDS: tokens/compile] finished: compile command with compile variable compile-task
_46
Done in 1.17s.

Adding .storybook/themes.js

Create the file .storybook/themes.js...


_1
touch .storybook/themes.js

... and add the following content:

.storybook/themes.js
Copy

_38
import { create } from "@storybook/theming";
_38
import * as tokens from '../src/token/storybook/tokens';
_38
_38
export const light = create({
_38
base: "light",
_38
_38
colorPrimary: tokens.KsColorPrimaryBase,
_38
colorSecondary: tokens.KsColorPrimaryBase,
_38
_38
// UI
_38
appBg: tokens.KsColorPrimaryToBg9Base,
_38
appContentBg: tokens.KsBackgroundColorDefaultBase,
_38
appBorderColor: tokens.KsColorPrimaryAlpha2Base,
_38
appBorderRadius: tokens.KsBorderRadiusCard,
_38
_38
// Typography
_38
fontBase: tokens.KsFontFamilyInterface,
_38
fontCode: tokens.KsFontFamilyMono,
_38
_38
// Text colors
_38
textColor: tokens.KsTextColorDefaultBase,
_38
textInverseColor: tokens.KsTextColorDefaultInvertedBase,
_38
_38
// Toolbar default and active colors
_38
barTextColor: tokens.KsColorPrimaryAlpha6Base,
_38
barSelectedColor: tokens.KsColorPrimaryBase,
_38
barBg: tokens.KsBackgroundColorDefaultBase,
_38
_38
// Form colors
_38
inputBg: tokens.KsBackgroundColorInterfaceInteractiveBase,
_38
inputBorder: tokens.KsColorFgToBg7Base,
_38
inputTextColor: tokens.KsTextColorInterfaceInteractiveBase,
_38
inputBorderRadius: tokens.KsBorderRadiusControl,
_38
_38
brandTitle: "Your kickstartDS Storybook",
_38
brandUrl: "https://www.kickstartDS.com",
_38
brandImage: "/logo.svg",
_38
});

We import the create function from Storybook and our token. With those we create a new theme, with light as the base. We won't go into detail about the specific token applications now, but feel free to adjust brandTitle and brandUrl to your liking! brandImage will be added next...

Create a folder static on your project root now:


_1
mkdir -p static

For this to work, we add our logo to the static/ directory created before, as logo.svg. If you don't have a fitting logo laying around now, feel free to just use ours (right click > save as).

Adding .storybook/manager.js

Now create the second file needed, .storybook/manager.js...


_1
touch .storybook/manager.js

... and add this code to it:

.storybook/manager.js
Copy

_4
import { addons } from "@storybook/addons";
_4
import { light } from "./themes";
_4
_4
addons.setConfig({ theme: light });

We import addons from Storybook, and our newly created theme from .storybook/themes.js. We combine those to apply our theme to Storybook.

Add a fitting favicon

Our final addition for this section includes changing .storybook/manager-head.html again. Add the following lines to it:

.storybook/manager-head.html
Copy

_8
<link rel="stylesheet" href="manager.css" />
_8
<link rel="shortcut icon" href="/favicon/favicon.ico" />
_8
<link
_8
rel="icon"
_8
type="image/png"
_8
href="/favicon/favicon-192-192.png"
_8
sizes="192x192"
_8
/>

This adds a good looking, custom favicon to our Storybook when opened in the browser, which really helps to find your own Design System... in a sea of tabs 😅.
The configuration expects the files favicon/favicon.ico and favicon/favicon-192-192.png to be placed in our static/ folder, like it was the case for logo.svg before.

Create the sub directory...


_1
mkdir -p static/favicon

... and place your files inside. If you need something to continue, feel free to use our favicon.ico (right click > save as) and favicon-192-192.png (right click > save as) for now!

Finalizing Storybook theming

If you start your Storybook now (yarn storybook), you should feel right at home! You should see your own logo, your own colors and your font being applied to Storybook itself (or the ones you've used while testing around). Giving it your own, unique flavour... without being distracting!

As we've added one new generated file, we make sure to include it in our .gitignore:

.gitignore
Copy

_13
# Node
_13
node_modules
_13
_13
# Storybook
_13
storybook-static
_13
_13
# kickstartDS
_13
src/token/tokens.css
_13
src/token/storybook/tokens.css
_13
src/token/storybook/tokens.js
_13
src/token/storybook/icons.svg
_13
static/manager.css
_13
static/manager.css.map

Integrate with kickstartDS

What follows is in preparation for the next big chapter, adding components. It will have no immediately visible effect now, next to a small test component that we'll add to the Welcome page, but ensures a smoother experience going forward... without having to return to general setup tasks all the time.

Integration consists mainly of adding glue code and snippets to the Storybook configuration, to tell it about the existence of kickstartDS. How code should be handled, where CSS is located, and how our Icons work!

Transpile @kickstartDS components

Base components installed as part of @kickstartDS dependencies (e.g. @kickstartDS/base) are placed in your node_modules after installation. For those components to be compatible with Storybook, and its build & compilation pipeline, we need to ensure that they get transpiled (like your local code automatically is). Add the following webpackFinal configuration to .storybook/main.js:

.storybook/main.js
Copy

_52
const path = require("path");
_52
_52
module.exports = {
_52
stories: [
_52
"../src/**/*.stories.mdx",
_52
"../src/**/*.stories.@(js|jsx|ts|tsx)",
_52
"../docs/**/*.stories.mdx",
_52
],
_52
addons: [
_52
"@storybook/addon-links",
_52
"@storybook/addon-essentials",
_52
"@storybook/addon-interactions",
_52
{
_52
name: "storybook-design-token",
_52
options: { designTokenGlob: "src/token/storybook/*" },
_52
},
_52
],
_52
framework: "@storybook/react",
_52
staticDirs: ["../static"],
_52
features: {
_52
postcss: false,
_52
},
_52
async webpackFinal(config, { configType }) {
_52
const babelRuleIndex = config.module.rules.findIndex((rule) =>
_52
rule?.use?.some((u) => u?.loader.includes("babel-loader"))
_52
);
_52
_52
config.module.rules[babelRuleIndex].exclude =
_52
/node_modules\/(?!(@kickstartds\/))/;
_52
_52
config.module.rules.push({
_52
test: /\.scss$/,
_52
use: [
_52
"style-loader",
_52
"css-loader",
_52
{
_52
loader: "sass-loader",
_52
options: {
_52
sassOptions: {
_52
includePaths: [path.resolve(__dirname, "../node_modules")],
_52
},
_52
},
_52
},
_52
],
_52
include: path.resolve(__dirname, "../src"),
_52
});
_52
_52
config.resolve.mainFields = ["browser", "module", "main"];
_52
_52
return config;
_52
},
_52
}

This sets up everything needed to import components from @kickstartDS (e.g. import { Button } from "@kickstartds/base/lib/button"). First we add exemptions to the babel-loader for JavaScript code transpilation, which normally ignores code in node_modules. Additionally we add loaders for CSS / SCSS, allow includes from node_modules, configure the path our code lives in, and configure mainFields (learn about them here).

Read more about Storybooks Webpack builder, or Webpack in general, for details.

Adding a demo Button

To test our Storybook setup and integration actually works, we add a Button to our Welcome page.

docs/welcome.stories.mdx
Copy

_18
import { Meta } from "@storybook/addon-docs";
_18
import { Button } from "@kickstartds/base/lib/button";
_18
_18
<Meta title="Welcome" />
_18
_18
# Your kickstartDS based Design System
_18
_18
Ipsum voluptate reprehenderit ut aliquid laborum enim. Optio et suscipit aliquam voluptate nostrum est. Corrupti ab laboriosam qui aut aliquid iusto nobis voluptatum. Perferendis non reiciendis illum. Vel et sint est.
_18
_18
Alias placeat accusantium voluptatem pariatur dolor et. Dicta quia officia voluptatem quia nulla natus. Accusantium in voluptate porro. Libero voluptatem placeat ipsum dolores deserunt omnis odio.
_18
_18
Sed distinctio consequuntur et et aliquid. Exercitationem autem impedit expedita. Beatae eum voluptatem eaque necessitatibus repellendus. Velit qui est optio. Ut est voluptates incidunt et qui sed dolorem. Quidem molestiae velit non laudantium consequatur autem.
_18
_18
Amet doloremque voluptas suscipit. Omnis incidunt sit nesciunt voluptate sed voluptatem delectus quis. Repudiandae occaecati magni fugit. Minus sunt quia ab temporibus. Voluptatibus vel odit facere enim et.
_18
_18
Consequatur et consequuntur et. Nam consequatur sed voluptas ea. Tempore vero velit et hic. Ut et aspernatur quaerat ut aut consequatur. Quisquam aliquid ea adipisci nulla quia ut dolor. Accusamus earum quasi quaerat.
_18
_18
<Button label="Learn more"/>

First we import the Button component from @kickstartds/base/lib/button, to then add it to the end of the page with a label of "Learn more". To see all available options for such a Button component have a look at our Storybook.

If not still running, start your Storybook again now (yarn storybook), and browse to the Welcome page. You should be greeted by your newly added Button there. But there's something missing. It's not looking quite right, yet!

Add missing styles in preview.js

We need some base styles and JavaScript provided by @kickstartds/base, and our own Design Token set, the one converted to CSS custom properties in src/token/tokens.css.

Add the following lines to your .storybook/preview.js:

.storybook/preview.js
Copy

_30
import "@kickstartds/base/lib/global/base.js";
_30
import "@kickstartds/base/lib/global/base.css";
_30
_30
import "../src/token/tokens.css";
_30
_30
export const parameters = {
_30
actions: { argTypesRegex: "^on[A-Z].*" },
_30
controls: {
_30
matchers: {
_30
color: /(background|color)$/i,
_30
date: /Date$/,
_30
},
_30
},
_30
options: {
_30
storySort(a, b) {
_30
// welcome page to top!
_30
if (a[0].includes("welcome")) {
_30
return -1;
_30
}
_30
_30
// alphabetically
_30
return a[1].kind === b[1].kind
_30
? 0
_30
: a[1].id.localeCompare(b[1].id, undefined, { numeric: true });
_30
},
_30
},
_30
designToken: {
_30
disable: true,
_30
},
_30
}

Re-start Storybook to revisit the Welcome page. Everything should be looking as expected now!

Adding an Icon to our Button

As a small motivation for the next section, change the Button markup in docs/welcome.stories.jsx slightly:

docs/welcome.stories.jsx
Copy

_18
import { Meta } from "@storybook/addon-docs";
_18
import { Button } from "@kickstartds/base/lib/button";
_18
_18
<Meta title="Welcome" />
_18
_18
# Your kickstartDS based Design System
_18
_18
Ipsum voluptate reprehenderit ut aliquid laborum enim. Optio et suscipit aliquam voluptate nostrum est. Corrupti ab laboriosam qui aut aliquid iusto nobis voluptatum. Perferendis non reiciendis illum. Vel et sint est.
_18
_18
Alias placeat accusantium voluptatem pariatur dolor et. Dicta quia officia voluptatem quia nulla natus. Accusantium in voluptate porro. Libero voluptatem placeat ipsum dolores deserunt omnis odio.
_18
_18
Sed distinctio consequuntur et et aliquid. Exercitationem autem impedit expedita. Beatae eum voluptatem eaque necessitatibus repellendus. Velit qui est optio. Ut est voluptates incidunt et qui sed dolorem. Quidem molestiae velit non laudantium consequatur autem.
_18
_18
Amet doloremque voluptas suscipit. Omnis incidunt sit nesciunt voluptate sed voluptatem delectus quis. Repudiandae occaecati magni fugit. Minus sunt quia ab temporibus. Voluptatibus vel odit facere enim et.
_18
_18
Consequatur et consequuntur et. Nam consequatur sed voluptas ea. Tempore vero velit et hic. Ut et aspernatur quaerat ut aut consequatur. Quisquam aliquid ea adipisci nulla quia ut dolor. Accusamus earum quasi quaerat.
_18
_18
<Button iconAfter={{ icon: 'chevron-right' }} label="Learn more"/>

We add an Icon to the button using iconAfter (you can use iconAfter or iconBefore, or both!). To see a list of available Icons you can have a look at your Storybook. It should have a page titled Icons in the Design Tokens category. This has all of your .svg icons compiled, all those are possible inputs for icon here.

To see all options available on a Button, have a look at its documentation in Storybook (either in our docs, or locally through the composed docs in your sidebar).

If you re-check your Welcome page in the browser again now, you'll see the button having space reserved for an Icon. But the Icon itself is still missing. This is because we haven't included our Icon Sprite for component previews in Storybook, yet. The only reason they're successfully displayed on your Icons page currently, is that the storybook-design-token addon is picking them up using its own loader.

Let's add our Icon Sprite to Storybook for real, now!

Integrate Icons with Storybook previews

Instead of loading a bunch of single files per icon, we encourage compiling all your SVGs into one sprite. We offer different output formats for that through the pre-configured Style Dictionary in use (SVG, HTML, React). This can be included once in the page, and the elements will just be referenced. Learn more about sprites with <symbol> and <use> on MDN.

As with other changes that had to do with how Storybook renders our own components (in a preview context), we will need to adjust .storybook/preview.js again to integrate kickstartDS and Storybook:

.storybook/preview.js
Copy

_51
import { DocsContainer } from "@storybook/addon-docs";
_51
_51
import "@kickstartds/base/lib/global/base.js";
_51
import "@kickstartds/base/lib/global/base.css";
_51
_51
import IconSprite from "../src/token/icons/IconSprite";
_51
_51
import "../src/token/tokens.css";
_51
_51
export const parameters = {
_51
actions: { argTypesRegex: "^on[A-Z].*" },
_51
controls: {
_51
matchers: {
_51
color: /(background|color)$/i,
_51
date: /Date$/,
_51
},
_51
},
_51
options: {
_51
storySort(a, b) {
_51
// welcome page to top!
_51
if (a[0].includes("welcome")) {
_51
return -1;
_51
}
_51
_51
// alphabetically
_51
return a[1].kind === b[1].kind
_51
? 0
_51
: a[1].id.localeCompare(b[1].id, undefined, { numeric: true });
_51
},
_51
},
_51
designToken: {
_51
disable: true,
_51
},
_51
docs: {
_51
container: (props) => (
_51
<>
_51
<IconSprite />
_51
<DocsContainer {...props} />
_51
</>
_51
),
_51
},
_51
};
_51
_51
export const decorators = [
_51
(Story) => (
_51
<>
_51
<IconSprite />
_51
<Story />
_51
</>
_51
),
_51
];

We wrap Storybooks story rendering in two places. Firstly we import the default DocsContainer from @storybook/addon-docs and our Icons from ../src/token/icons/IconSprite, to then ensure that every time a docs page is rendered, our Icons get included there, too. Secondly we add our first decorator to the decorators array, also adding our imported Icons. This one is concerned with all the other story previews there are, read more about decorators here.

You might have stumbled over our Icons import above: import IconSprite from "../src/token/icons/IconSprite". That file doesn't actually exist (yet)! You might also recall how we've added annotated Design Token before, by adding a new transform to our Style Dictionary configuration. We'll now add another transform to it that takes our Icons and converts them to a JSX component-variant of our IconSprite, ready to be imported in .storybook/preview.js:

sd.config.js
Copy

_31
const path = require('path');
_31
const StyleDictionary = require("style-dictionary");
_31
const { config } = require("@kickstartds/style-dictionary");
_31
_31
module.exports = StyleDictionary.extend(config).extend({
_31
source: [
_31
"src/token/dictionary/**/*.json",
_31
path.join(path.dirname(require.resolve('@kickstartds/core/package.json')), 'source/design-tokens/icons/*.svg')
_31
],
_31
platforms: {
_31
css: {
_31
buildPath: 'src/token/'
_31
},
_31
jsx: {
_31
buildPath: 'src/token/icons/'
_31
},
_31
storybook: {
_31
buildPath: 'src/token/storybook/'
_31
},
_31
js: {
_31
transforms: ["attribute/cti", "name/cti/pascal", "size/rem", "color/css"],
_31
buildPath: "src/token/storybook/",
_31
files: [
_31
{
_31
destination: "tokens.js",
_31
format: "javascript/es6",
_31
},
_31
],
_31
},
_31
},
_31
});

And, you know the drill by now, after changing our sd.config.js we'll want to re-compile our Style Dictionary...


_1
yarn build-tokens

... to find a new output for jsx in the log, written to src/token/icons/IconSprite.js, as referenced by .storybook/preview.js:


_49
yarn run v1.22.18
_49
$ kickstartDS tokens compile
_49
_ _ _ _ _ ____ ____
_49
| | _(_) ___| | _____| |_ __ _ _ __| |_| _ \/ ___|
_49
| |/ / |/ __| |/ / __| __/ _` | '__| __| | | \___ \
_49
| <| | (__| <\__ \ || (_| | | | |_| |_| |___) |
_49
|_|\_\_|\___|_|\_\___/\__\__,_|_| \__|____/|____/
_49
_49
______________/\\\\\\\\\__/\\\______________/\\\\\\\\\\\_______
_49
___________/\\\////////__\/\\\_____________\/////\\\///________
_49
_________/\\\/___________\/\\\_________________\/\\\___________
_49
________/\\\_____________\/\\\_________________\/\\\___________
_49
_______\/\\\_____________\/\\\_________________\/\\\___________
_49
_______\//\\\____________\/\\\_________________\/\\\___________
_49
________\///\\\__________\/\\\_________________\/\\\___________
_49
__/\\\____\////\\\\\\\\\_\/\\\\\\\\\\\\\\\__/\\\\\\\\\\\__/\\\_
_49
_\///________\/////////__\///////////////__\///////////__\///__
_49
_49
Version: 1.0.0
_49
For more information visit:
_49
https://www.kickstartDS.com/docs/intro/cli
_49
_49
Starting...
_49
[kickstartDS: general] [info]: welcome to the kickstartDS CLI
_49
[kickstartDS: tokens/compile] starting: compile command with compile variable compile-task
_49
[1/1] [compile: check] [info]: checking prerequesites before starting
_49
[1/1] [compile: check] [info]: prerequesites met, starting
_49
[compile: cleanup] [info]: cleaning up temp dir /tmp/tokens-compile-compile-task before starting command
_49
[compile: cleanup] [info]: finished cleaning up temp dir /tmp/tokens-compile-compile-task before starting command
_49
[1/1] [compile: compile] [info]: running the compile subtask
_49
[1/1] [compile: compile] [info]: getting Style Dictionary from token files
_49
[1/1] [compile: compile] [info]: compiling Style Dictionary to needed CSS and assets
_49
_49
css
_49
✔︎ src/token/tokens.css
_49
_49
jsx
_49
✔︎ src/token/icons/IconSprite.js
_49
_49
storybook
_49
✔︎ src/token/storybook/tokens.css
_49
✔︎ src/token/storybook/icons.svg
_49
_49
js
_49
✔︎ src/token/storybook/tokens.js
_49
[1/1] [compile: compile] [info]: copying generated CSS and assets to local folder
_49
[1/1] [compile: compile] [info]: finished running the compile subtask successfully
_49
[kickstartDS: tokens/compile] finished: compile command with compile variable compile-task
_49
Done in 1.49s.

(Re-)open your Storybook now and change to the Welcome page. You should be greeted by a Button with its Icon visible, as configured in the component props!

Like before, we make sure to include the newly generated file in our .gitignore:

.gitignore
Copy

_14
# Node
_14
node_modules
_14
_14
# Storybook
_14
storybook-static
_14
_14
# kickstartDS
_14
src/token/tokens.css
_14
src/token/icons/IconSprite.js
_14
src/token/storybook/tokens.css
_14
src/token/storybook/tokens.js
_14
src/token/storybook/icons.svg
_14
static/manager.css
_14
static/manager.css.map

Integrate kickstartDS radio with Storybook actions

We use a small, light-weight communication component called radio (basically a mini PubSub) in all existing components for communication and event handling. It's part of our Core (@kickstartDS/core) architecture. To make debugging easier and more transparent, we connect our radio with Storybooks actions, and their actions addon.

Configuration is pretty easy, just add the following lines to .storybook/preview.js:

.storybook/preview.js
Copy

_55
import { actions } from "@storybook/addon-actions";
_55
import { DocsContainer } from "@storybook/addon-docs";
_55
_55
import "@kickstartds/base/lib/global/base.js";
_55
import "@kickstartds/base/lib/global/base.css";
_55
_55
import IconSprite from "../src/token/icons/IconSprite";
_55
_55
import "../src/token/tokens.css";
_55
_55
const myActions = actions("radio");
_55
window._ks.radio.on("*", myActions.radio);
_55
_55
export const parameters = {
_55
actions: { argTypesRegex: "^on[A-Z].*" },
_55
controls: {
_55
matchers: {
_55
color: /(background|color)$/i,
_55
date: /Date$/,
_55
},
_55
},
_55
options: {
_55
storySort(a, b) {
_55
// welcome page to top!
_55
if (a[0].includes("welcome")) {
_55
return -1;
_55
}
_55
_55
// alphabetically
_55
return a[1].kind === b[1].kind
_55
? 0
_55
: a[1].id.localeCompare(b[1].id, undefined, { numeric: true });
_55
},
_55
},
_55
designToken: {
_55
disable: true,
_55
},
_55
docs: {
_55
container: (props) => (
_55
<>
_55
<IconSprite />
_55
<DocsContainer {...props} />
_55
</>
_55
),
_55
},
_55
};
_55
_55
export const decorators = [
_55
(Story) => (
_55
<>
_55
<IconSprite />
_55
<Story />
_55
</>
_55
),
_55
];

Now everytime a kickstartDS component emits an event over radio, it will be displayed in the Actions tab in Storybook.

Install remaining addons

Like the last step, this one will also mostly be done in preparation. We add some more addons, that each add a specific view of your components to Storybook:

  • HTML rendering addon
  • JSON Schema addon
  • Component Token addon

This will give you a great overview of all aspects that make up a component in a Design System in general, and with kickstartDS specifically. Especially helpful while adding components in the next main chapter of this guide!

First add the addons to your project:


_1
yarn add -D @kickstartds/storybook-addon-component-tokens @kickstartds/storybook-addon-jsonschema @whitespace/storybook-addon-html@git+https://github.com/lmestel/storybook-addon-html.git

Fork of @whitespace/storybook-addon-html

We currently need a fork of @whitespace/storybook-addon-html, because the original version of the addon just takes the HTML from the browser. This is problematic, because it means that markup might already be manipulated by client-side JavaScript (e.g. some classes being added). For our use, copy & paste of the initial HTML, we've switched the addon to use Reacts SSR Renderer.

To activate those addons, we need to add them to .storybook/main.js, too. They don't need any further configuration:

.storybook/main.js
Copy

_55
const path = require("path");
_55
_55
module.exports = {
_55
stories: [
_55
"../src/**/*.stories.mdx",
_55
"../src/**/*.stories.@(js|jsx|ts|tsx)",
_55
"../docs/**/*.stories.mdx",
_55
],
_55
addons: [
_55
"@storybook/addon-links",
_55
"@storybook/addon-essentials",
_55
"@storybook/addon-interactions",
_55
{
_55
name: "storybook-design-token",
_55
options: { designTokenGlob: "src/token/storybook/*" },
_55
},
_55
"@whitespace/storybook-addon-html",
_55
"@kickstartds/storybook-addon-component-tokens",
_55
"@kickstartds/storybook-addon-jsonschema",
_55
],
_55
framework: "@storybook/react",
_55
staticDirs: ["../static"],
_55
features: {
_55
postcss: false,
_55
},
_55
async webpackFinal(config, { configType }) {
_55
const babelRuleIndex = config.module.rules.findIndex((rule) =>
_55
rule?.use?.some((u) => u?.loader.includes("babel-loader"))
_55
);
_55
_55
config.module.rules[babelRuleIndex].exclude =
_55
/node_modules\/(?!(@kickstartds\/))|core-js/;
_55
_55
config.module.rules.push({
_55
test: /\.scss$/,
_55
use: [
_55
"style-loader",
_55
"css-loader",
_55
{
_55
loader: "sass-loader",
_55
options: {
_55
sassOptions: {
_55
includePaths: [path.resolve(__dirname, "../node_modules")],
_55
},
_55
},
_55
},
_55
],
_55
include: path.resolve(__dirname, "../src"),
_55
});
_55
_55
config.resolve.mainFields = ["browser", "module", "main"];
_55
_55
return config;
_55
},
_55
}

Fork of @whitespace/storybook-addon-html

We deactivate @kickstartds/storybook-addon-jsonschema for now, because there's a bug that needs to be fixed to make it compatible with the Open Source 2.0.0 release of kickstartDS. You can follow the progress for this on the following ticket: kickstartDS/storybook-addon-jsonschema/issues/19

Review changes

Let us review our package.json again now, it's starting to grow already:

HTML rendering addon

We use @whitespace/storybook-addon-html to add a tab to every component Canvas sidebar, where you can copy the currently configured component as a plain HTML component.

Design Token addon

For Design Token documentation we use storybook-design-token. Mainly for its DesignTokenDocBlock component, which helps rendering the pages we'll create to display our Design Token set.

JSON Schema addon

We use our own @kickstartds/storybook-addon-jsonschema to display our component structure / API in a Canvas tab, alongside the component.

Read more about it on our dedicated integration page.

Component Token addon

For this we use another Canvas and tab based addon we've written ourselves, to visualize your Component Token: @kickstartds/storybook-addon-component-token. Especially helps discovering the token layering applied to a component.

Read more about it on our dedicated integration page.

package.json
Copy

_40
{
_40
"name": "@my/design-system",
_40
"version": "1.0.0",
_40
"description": "Design System for all @MY needs",
_40
"main": "dist/index.js",
_40
"scripts": {
_40
"build-storybook": "build-storybook",
_40
"build-tokens": "kickstartDS tokens compile",
_40
"init-tokens": "kickstartDS tokens init",
_40
"sass-manager": "sass --load-path=node_modules .storybook/manager.scss static/manager.css",
_40
"storybook": "start-storybook -p 6006",
_40
"test": "echo \"Error: no test specified\" && exit 1",
_40
"watch:sass-manager": "yarn sass-manager --watch"
_40
},
_40
"author": "Jonas Ulrich",
_40
"license": "MIT",
_40
"dependencies": {
_40
"@kickstartds/base": "^2.0.2",
_40
"kickstartds": "^1.0.0",
_40
"react": "^17.0.2",
_40
"react-dom": "^17.0.2"
_40
},
_40
"devDependencies": {
_40
"@babel/core": "^7.19.3",
_40
"@kickstartds/storybook-addon-component-tokens": "^0.1.6",
_40
"@kickstartds/storybook-addon-jsonschema": "^1.0.5",
_40
"@storybook/addon-actions": "^6.5.12",
_40
"@storybook/addon-essentials": "^6.5.12",
_40
"@storybook/addon-interactions": "^6.5.12",
_40
"@storybook/addon-links": "^6.5.12",
_40
"@storybook/builder-webpack4": "^6.5.12",
_40
"@storybook/manager-webpack4": "^6.5.12",
_40
"@storybook/react": "^6.5.12",
_40
"@storybook/testing-library": "^0.0.13",
_40
"@whitespace/storybook-addon-html": "git+https://github.com/lmestel/storybook-addon-html.git",
_40
"babel-loader": "^8.2.5",
_40
"sass": "^1.56.0",
_40
"storybook-design-token": "^2.8.0"
_40
}
_40
}

Result

With that, we've successfully added Storybook to our Design System, integrated it with our Design Token / Style Dictionary, adopted some concepts of kickstartDS, and even added a bit of theming! We have our main setup running now, including Storybook.

Next Step

It's time to get to the exciting part... adding components to our Design System. To learn about the different ways you can go about in that, follow our next section!

Code Sandbox

See the result of this step in the Code Sandbox below. It's showing specifically the result after this step. You can also view this on Github directly in the ds-guide repository, there's a branch for every step... and we're currently on the branch step/3 in the guide:

Toggle the file browser with the hamburger icon at the top left, or open it directly in your browser.