DEV Community

Cover image for How to build a reusable component library using Svelte and Storybook
Gift Opia
Gift Opia

Posted on • Updated on

How to build a reusable component library using Svelte and Storybook

Libraries are a very important consideration in building large applications because they prevent you from writing a large number of codes and logic that have already been prebuilt.

This article aims to give readers an introduction to building reusable components using Storybook (To visually test your component) and Svelte (To build the actual component).

We will be creating a simple button library that allows users to create styled buttons with just one line of code.

What is Storybook?

Storybook is a tool for UI development that makes development faster and easier by isolating components. This also has an environment for us to view our components. You can check Storybook documentation for more.

Quick introduction to Svelte

According to its blog, Svelte is a component framework — like React or Vue — but with an important difference; unlike other frameworks, Svelte runs at build time, converting your components into highly efficient imperative code that surgically updates the DOM. As a result, you're able to write ambitious applications with excellent performance characteristics.

So what the above explanations simply mean is that Svelte doesn’t work like other frameworks that use “virtual doms” to update the UI rather, it compiles component files into beautifully optimized JavaScript behind the scenes. So yes, Svelte is just a compiler rather than a framework!

Assumptions

This article assumes that you are already familiar with HTML, CSS, JavaScript, and Svelte basics. No worries, no prior experience of Storybook is necessary.

Getting started with Storybook

We will be using the Storybook + Svelte boilerplate to set up our application and the first thing we need to do is to use degit to set up our boilerplates.
Run the following commands:

# Clone template
npx degit chromaui/intro-storybook-svelte-template svelte-button

cd svelte-button

# Install dependencies
npm install
Enter fullscreen mode Exit fullscreen mode

If all has gone well so far, run the following command:

npm run storybook
Enter fullscreen mode Exit fullscreen mode

The Storybook will be opened on localhost:6006 and you will see a screen just like this;

Image of Storybook testing environment

Now you can take a sip of coffee as you are one step closer to building your Svelte library.

File structure

There are important files and folders to pay close attention to in the template you generated earlier. They include;

  • rollup.config.js
  • src/main.js
  • src/stories

rollup.config.js

The rollup.config.js file contains metadata as to how the svelte compiler should read and compile the entire code. Therefore, we have to carefully understand how the compiler is set so we know how to structure our codebase properly.

So, the input portion of it like that in the code below tells the compiler where to look when compiling. Therefore, our main components will be exported.

export default {
  input: "src/main.js",
  output: {
    sourcemap: true,
    format: "iife",
    name: "app",
    file: "public/build/bundle.js",
  }
}
Enter fullscreen mode Exit fullscreen mode

src/main.js

By default we would get something like this;

import App from './App.svelte';

const app = new App({
  target: document.body,
  props: {
    name: 'world'
  }
});

export default app;

Enter fullscreen mode Exit fullscreen mode

This is a basic way to pass props between components in Svelte but we won't be needing this. But at the end of the project, we’d have something like this;

export { default as Button } from './components/buttons/Button.svelte'
Enter fullscreen mode Exit fullscreen mode

src/stories

The stories folder would contain .stories.js files for different components. In these files, we would write our storybook code to help us test our code visually.

You can go ahead to clear the files in this folder for we would be creating ours.

Creating the button component

Firstly, I'd like us to delete every file and folder in the src folder except the main.js file as that is our root file.

In our src folder, we'll create a "components" folder where we'll store, individually, every component our library should have. But in this article, we'd have just one component; The buttons component.
In our newly created components folder, we'll create a "buttons" folder where we'll store every code related to the button component. In our buttons folder, we'll create a Button.svelte file.

src                     
└─ components            
    └─ buttons           
      └─ Button.svelte              
Enter fullscreen mode Exit fullscreen mode

The next thing we want to do is create our button element and give it some dynamic class names so that it has different styles as requested.

<script>
  export let value
  export let size = 'md';
  export let type = 'default';
  export let shape = 'default';
  export let outlined = false;

  const outlinedClass = outlined
    ? `gl-btn-outlined gl-btn-outlined-${type}`
    : `gl-btn-${type}`;
</script>

  <button class="gl-btn gl-btn-{shape} gl-btn-{size} {outlinedClass}">
    {value}
  </button>

Enter fullscreen mode Exit fullscreen mode

Now that we have specified what our button component should be, let's write our styles to fit every use cases that we want.

<script>
  export let value
  export let size = 'md';
  export let type = 'default';
  export let shape = 'default';
  export let outlined = false;

  const outlinedClass = outlined
    ? `gl-btn-outlined gl-btn-outlined-${type}`
    : `gl-btn-${type}`;
</script>

  <button class="gl-btn gl-btn-{shape} gl-btn-{size} {outlinedClass}">
    {value}
  </button>


<style>
  .gl-btn {
    border-radius: 5px;
    cursor: pointer;
  }
  .gl-btn-outlined {
    background: transparent !important;
  }
  .gl-btn-pill {
    border-radius: 50px;
  }
  .gl-btn-sm {
    padding: 10px 20px;
  }
  .gl-btn-md {
    padding: 13px 32px;
  }
  .gl-btn-lg {
    font-size: larger;
    padding: 15px 50px;
  }
  .gl-btn-primary{
    color: white;
    background: #0275d8;
    border: #0275d8
  }
  .gl-btn-outlined-primary {
    color: #0275d8;
    border: 1px #0275d8 solid
  }
  .gl-btn-success{
    color: white;
    background: #5cb85c;
    border: #5cb85c;
  }
  .gl-btn-outlined-success {
    color: #5cb85c;
    border: 1px #5cb85c solid
  }
  .gl-btn-secondary{
    color: white;
    border: grey;
    background: grey;
  }

  .gl-btn-outlined-secondary{
    color: grey;
    border: 1px grey solid;
  }

  .gl-btn-danger{
    color: white;
    background: #d9534f;
    border: #d9534f;
  }
  .gl-btn-outlined-danger{
    color: #d9534f;
    border: 1px #d9534f solid;
  }
  .gl-btn-warning{
    color: white;
    background: #f0ad4e;
    border: #f0ad4e
  }
  .gl-btn-outlined-warning{
    color: #f0ad4e;
    border: 1px #f0ad4e solid
  }
  .gl-btn-info{ color: white;
    background: #5bc0de;
    border: #5bc0de;
  }
  .gl-btn-outlined-info{
    color: #5bc0de;
    border: 1px #5bc0de solid;
  }
  .gl-btn-light{
    background: #f7f7f7;
    border: #f7f7f7;
  }
  .gl-btn-dark{
    color: white;
    background: #292b2c;
    border: #292b2c;
  }
  .gl-btn-outlined-dark{
    color: #292b2c;
    border: 1px #292b2c solid;
  }
  .gl-btn-link{
    background: transparent;
    border: transparent;
    color: #0275d8;
  }
  .gl-btn-link:hover {
    text-decoration: underline;
  }

</style>

Enter fullscreen mode Exit fullscreen mode

Note, you can store your css anywhere, I just chose to store mine in the same file.

Finally, we'll export our Button component in the main.js file for reusability by replacing the existing code with this;

export { default as Button } from './components/buttons/Button.svelte'
Enter fullscreen mode Exit fullscreen mode

Creating the storybook visual test

Storybook helps document components for reuse and automatically visually test your components to prevent bugs.

Firstly, we will create a stories folder in our src folder, and in our stories folder, we'll create a button.stories.js file.

src                      
└─ stories               
  └─ button.stories.js  
Enter fullscreen mode Exit fullscreen mode

Step1: Importing our Button component

import Button from '../components/buttons/Button.svelte'
Enter fullscreen mode Exit fullscreen mode

Step2: Exporting the component to storybook

export default {
    title: 'Button',
    component: Button
}
Enter fullscreen mode Exit fullscreen mode

This would be displayed in Storybook as the folder titled "Button" holding all your test cases.

Step3: Writing the main visual tests

export const Default = () => ({
    Component: Button,
    props: {
        value: 'Button'
    }
})

export const Success = () => ({
    Component: Button,
    props: {
        value: 'Button',
        type: 'success'
    }
})
Enter fullscreen mode Exit fullscreen mode

You should see a screen just like this:

Default button

Success button

And your button.stories.js file should look like this:

import Button from '../components/buttons/Button.svelte'

export default {
    title: 'Button',
    component: Button
}

export const Default = () => ({
    Component: Button,
    props: {
        value: 'Button'
    }
})

export const Success = () => ({
    Component: Button,
    props: {
        value: 'Button',
        type: 'success'
    }
})
Enter fullscreen mode Exit fullscreen mode

Now that wraps up our button component library. The library flow should look like the image above. I also added some more visual tests to the button.stories.js file, the source code is available at the end of the tutorial.

Publish to npm

This is the easiest segment.

Step1: Create an npm account

Visit npmjs.com and create an account if you haven't before.

Step2: Login to npm on your CLI

npm login
Enter fullscreen mode Exit fullscreen mode

You’ll be prompted to enter your username, password, and email address.
npm login

Step3: Publish

npm publish
Enter fullscreen mode Exit fullscreen mode

NOTE: Your package name can be changed in the package.json file.

Conclusion

With Svelte and Storybook, we were able to create a button component library with minimal effort.

The full source code of the app can be found here on Github. Trying out Storybook was very interesting and I recommend you read the documentation to see the magical things you could do with it. If you have any questions, don't hesitate to hit me up on Twitter: @theNameIsGiFTED

Top comments (3)

Collapse
 
nerdydave2017 profile image
NerdyDave2017

Nice

Collapse
 
iamgifted profile image
Gift Opia

Thanks :)

Collapse
 
danielrios549 profile image
Daniel Rios

How to get the props types and default values by default? Svelte uses export to create props, with Typescript it wouldn't be difficult to get this automatically...