How to build a reusable component library using Svelte and Storybook
Tags: svelte, storybook, javascript, beginners
Published: 2021-10-30 08:39:12

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](https://storybook.js.org/) for more.

## Quick introduction to Svelte
According to its [blog](https://svelte.dev/blog/svelte-3-rethinking-reactivity#What_is_Svelte), 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:
```bash
# Clone template
npx degit chromaui/intro-storybook-svelte-template svelte-button

cd svelte-button

# Install dependencies
npm install
```
If all has gone well so far, run the following command:
```
npm run storybook
```

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

![Image of Storybook testing environment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jhppkcuno831o60ca3cs.PNG)

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`

> <b>rollup.config.js<b/>

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.

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

> <b>src/main.js<b/>

By default we would get something like this;
```javascript
import App from './App.svelte';
 
const app = new App({
  target: document.body,
  props: {
    name: 'world'
  }
});
 
export default app;

```
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;
```javascript
export { default as Button } from './components/buttons/Button.svelte'
```

> <b>src/stories</b>

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.

```bash
src                     
└─ components            
    └─ buttons           
      └─ Button.svelte              
```

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.

```javascript
<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>

```

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

```javascript
<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>

```

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;
```javascript
export { default as Button } from './components/buttons/Button.svelte'
```

### 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.
```bash
src                      
└─ stories               
  └─ button.stories.js  
```  

#### Step1: Importing our Button component
```javascript
import Button from '../components/buttons/Button.svelte'
```

#### Step2: Exporting the component to storybook
```javascript
export default {
    title: 'Button',
    component: Button
}
```
This would be displayed in Storybook as the folder titled "Button" holding all your test cases.

#### Step3: Writing the main visual tests
```javascript
export const Default = () => ({
    Component: Button,
    props: {
        value: 'Button'
    }
})

export const Success = () => ({
    Component: Button,
    props: {
        value: 'Button',
        type: 'success'
    }
})
```
You should see a screen just like this:

![Default button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hx0qthu7f0xanvwytyi1.PNG)

![Success button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnrjbk2xqpy5hufsf8aw.PNG)

And your `button.stories.js` file should look like this: 
```javascript
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'
    }
})
```

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](https://www.npmjs.com/) and create an account if you haven't before.
### Step2: Login to npm on your CLI
```bash
npm login
```
You’ll be prompted to enter your username, password, and email address.
![npm login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0kenk4i5em3t58eopw2b.PNG)
### Step3: Publish
```bash
npm publish
```
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](https://github.com/Gift-Stack/svelte-button-library). Trying out Storybook was very interesting and I recommend you read the [documentation](https://storybook.js.org/docs/svelte/get-started/introduction) 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](https://twitter.com/thenameisgifted)