Create Interactive Style Guides with vue-styleguidist

Alex Jover Morales

Creating styleguides has been always hard work. It can take not only a huge amount of time, especially if you want to make it interactive, and it usually gets out of date as time goes by.

Vue-styleguidist is a nice and easy-to-use tool to create component style guides with interactive documentation in Vue.js. While Storybook for Vue has a manual approach to create interactive docs, vue-styleguidist statically analyzes your source code creating the docs automatically.

Setup vue-styleguidist

In your Vue.js project, install vue-styleguidist as a dev dependency from npm:

$ npm install --save-dev vue-styleguidist

Add the following two npm scripts to your package.json file:

package.json

{
  "scripts": {
    "styleguide": "vue-styleguidist server",
    "styleguide:build": "vue-styleguidist build"
  }
}

Finally, you have to setup some webpack config in order to make it work. If you already have a webpack.config.js in your project’s root, vue-styleguidist will load that config.

If that’s not the case, you must create a styleguide.config.js in your project’s root. In there, you could add the webpack config by loading it from another file:

styleguide.config.js

module.exports = {
  webpackConfig: require('./somewhere/webpack.config.js')
};

Or you could even load a different webpack config:

styleguide.config.js

module.exports = {
  webpackConfig: {
    module: {
      rules: [
        {
          test: /\.vue$/,
          exclude: /node_modules/,
          loader: "vue-loader"
        }
        // For js or css files:
        {
          test: /\.js?$/,
          exclude: /node_modules/,
          loader: "babel-loader"
        },
        {
          test: /\.css$/,
          loader: "style-loader!css-loader"
        }
      ]
    }
  }
};

In any case, remember to install the loaders you’re using, at least vue-loader.

Note that your project doesn’t have to use webpack. You could use other bundlers like Poi or Parcel. Styleguidist uses webpack internally, but it’s only needed for the required loaders.

Documenting a Component

vue-styleguidist will look for components using the glob pattern src/components/**/*.vue, but you can configure it using the components key in the styleguide.config.js file:

styleguide.config.js

module.exports = {
  components: "src/**/*.vue"
};

Using the default convention, let’s create the file src/components/AppButton.vue and paste the following simple component:

AppButton.vue

<template>
  <button :style="styles" @click="handleClick">
    <slot></slot>
  </button>
</template>

<script>
export default {
  name: "app-button",
  props: {
    color: {
      type: String,
      default: "black"
    },
    background: {
      type: String,
      default: "white"
    }
  },
  computed: {
    styles() {
      return {
        color: this.color,
        background: this.background
      };
    }
  },
  methods: {
    handleClick(e) {
      this.$emit("click", e);
    }
  }
};
</script>

The name component option is required.

Now run npm run styleguide, and you can navigate to the url displayed in the console, usually http://localhost:6060/. Out of the box, you’ll see the props are already documented on the component doc.

Keep in mind that only the components ins and outs must be documented. In Vue.js, those are props, slots and events.

Props

As you could see, props are documented by default using the type and default values, but we can add more options by adding JSDoc comments.

For example, we could add a description to the props:

AppButton.vue

{
  props: {
    /**
     * Sets the button font color
     */
    color: {
      type: String,
      default: "black"
    },
    /**
     * Sets background color of the button
     */
    background: {
      type: String,
      default: "white"
    }
  }
};

We could also mention that the background property is available since version 1.2.0 by using @since:

AppButton.vue

{
  props: {
    /** Sets background color of the button
     * @since 1.2.0
     */
    background: {
      type: String,
      default: "white"
    }
  }
};

As another example, we can mark a property as deprecated using @deprecated. That property will look crossed out:

AppButton.vue

{
  props: {
    /** Sets the button font color
     * @deprecated Use color instead
     */
    oldColor: String
  }
};

Slots

Slots can be documented by using an html-like comment right before the <slot> tag, using the @slot doc tag:

AppButton.vue

<template>
  <button :style="styles" @click="handleClick">
    <!-- @slot Use this slot to place the button content -->
    <slot></slot>
  </button>
</template>

You can use as many @slot comments as the number of slots you have, in case you use named slots.

Events

In Vue.js, events are emitted using this.$emit() function anywhere within methods.

Given that fact, events are documented by adding an @event comment, and it can be placed anywhere in the method where it’s emitted. They usually go along with @type in order to define the event payload type.

For clarity, I’d suggest placing them on the method definition:

AppButton.vue

{
  methods: {
    /** Triggered when button is clicked
     * @event click
     * @type {Event}
     */
    handleClick(e) {
      this.$emit("click", e);
    }
  }
}

If you emit several events, you can place just as many comments:

AppButton.vue

{
  methods: {
    /** Triggered when button is clicked
     * @event click
     * @type {Event}
     */

    /** Event for Alligator's example
     * @event gator
     * @type {Event}
     */
    handleClick(e) {
      this.$emit("click", e);
      this.$emit("gator", e);
    }
  }
}

Mixins

Mixins are objects which can contain props, methods and other logic to share between components.

Aside from documenting their props and events, they must include a @mixin doc tag in order to be recognized by vue-styleguidist.

For example, let’s create the following mixin:

sizeMixin.js

/**
 * @mixin
 */
export default {
  props: {
    /**
     * Set size of the element
     */
    size: {
      type: String,
      default: "14px"
    }
  }
};

And use it in the AppButton.vue component:

AppButton.vue

import sizeMixin from "./sizeMixin";

export default {
  name: "app-button",
  mixins: [sizeMixin],
  //...
}

Then, if you still have the styleguidist server running, you’ll see that the size prop got merged with the AppButton props.

Extended Docs and Examples

There are a few ways to add more docs to the component:

  • Adding a Readme.md file, if your component is within its own folder.
  • Adding a .md file with the same file name of the component.
  • Adding a <docs>...</docs> tag on the .vue file.

Since I like the approach and atomicity of single file components, I’m going for the options of using the <docs> tag. But you could choose the one you feel most comfortable with, the result is the same.

In there, you can add any static information, but the real potential is with examples. You can create an interactive example of the component just by adding the code like you’d do it in a markdown file.

The simplest form is by tagging the code blocks as jsx:

```jsx
<app-button color="orange">Push Me</app-button>
```

And for more complex examples, you could create your own vue instance, tagged as js:

```js
new Vue({
  data: () => ({
    message: ''
  }),
  template: `
    <div>
      <app-button color="orange" @click="message = 'clicked'">
        Push Me
      </app-button>

      {{message}}
    </div>
  `
})
```

Let’s therefore add a few examples to our AppButton component:

<docs>
This button is amazing, use it responsibly.

## Examples

Orange button:

```jsx
<app-button color="orange">Push Me</app-button>
```

Ugly button with pink font and blue background:

```jsx
<app-button color="pink" background="blue">
  Ugly button
</app-button>
```

Button containing custom tags:

```jsx
<app-button>
  Text with <b>bold</b>
</app-button>
```
</docs>

Wrapping Up

vue-styleguidist gives us a very easy and automated way to add docs to our components, ending up in a fully featured interactive style guide that other developers and designers can use and play around with.

You can download the complete example from this github repo.

Stay cool 🦄

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#