Getting Started with Blast – Storybook for Laravel Blade
Tags: tutorial, laravel, storybook, blade
Published: 2021-10-18 14:08:33

In this guide we'll show you how to set up a component library within your Laravel app using [Blast](https://github.com/area17/blast). 

## First of all, what is Blast?

At AREA 17, we've been using [Storybook](https://storybook.js.org/) for many years with both [Vue](https://vuejs.org/) and [React](https://reactjs.org/) and we love it, but our core technology is [Laravel](https://laravel.com/), and we want to be able to work with Storybook in that environment too. We've been able to in the past using the Twig loader, but our heart is closer to Blade. When Quentin, our Engineering Group Director, realized Storybook Server was a thing, and what the [Rails community was able to do with it](https://orbit.love/blog/building-a-component-library-in-rails-with-storybook), he started to dream big and threw a quick prototype at it. We then worked together to make that prototype a reality and it became **[Blast – Storybook for Laravel Blade](https://github.com/area17/blast)**.

Blast is a Laravel package which allows you render examples of your app's components using the Blade templating engine and Storybook Server within your Laravel application. It's designed to be low maintenance and simple to set up whilst offering a solid set of features and customizations. Blast can be used with new or existing Laravel projects - we timed it and it took less than 90s to install into an existing project and have our first component rendering in Storybook!

It comes with a lot of the tools we use at AREA 17 like the Controls, Accessibility testing and Design tabs as well as statuses and a page component for more global things like documentation.

Now that the introduction is over, let's get started!

## Installation

You can get started by installing Blast using:

```bash
composer require area17/blast
```

This will:

- Create a `stories` and a `data` directory for your story Blade files and any associated data
- Publish assets used by Blast to the application's public directory
- Create a route from which to load your component examples

Blast ships with 4 tasks:

- `blast:launch` - installs all dependencies, generates stories, watches directories and fires up Storybook Server
- `blast:generate-stories` - can be used to regenerate the stories.json files for each component outside of the `blast:launch` task
- `blast:demo` - creates a demo button component to help get you started
- `blast:publish` - generates a static Storybook instance and publishes it to your application's public directory

More information can be found about those tasks in the [official documentation](https://github.com/area17/blast#readme)

## Creating Stories

Once you've installed Blast you can launch it by running:

```bash
php artisan blast:launch
```

For this demo we'll create a basic button component and stories.

### Setup Components

For this guide we're going to need some basic components. We're going to need a `button`, `button-box` and some icons. You can find everything you'll need [in this repo](https://github.com/mrtimbrook/blast-guide-components). 

When you're done, your `components` directory should now look like this:

```
resources/views/components/
├── button/
│   └── primary.blade.php
├── button-box/
│   └── primary.blade.php
└── icon/
    ├── help-24.blade.php
    ├── menu-24.blade.php
    └── plus-24.blade.php
```

### Create a Story

Time to create your first story! When initially launching Blast, it created the directories to store your story blade files in `resources/views/stories` so, inside that directory, create `button/primary.blade.php` containing the following:

```php
<x-button.primary>
    Primary Button
</x-button.primary>
```

Hit save and Blast will automatically generate the stories for the component and reload storybook in your browser. Go check it out. Pretty cool huh? Maybe, but it's fairly basic and doesn't show what our button is capable of.

### Adding args

Let's create some Storybook controls to set the button label, icon and icon position.

Blast uses a `@storybook` directive to customize your story. You can read more about the options in the [Blast docs](https://github.com/area17/blast#readme).

Enter the following at the top of your `stories/button/primary.blade.php`:

```php
@storybook([
    'args' => [
        'label' => 'Button',
        'href' => '#',
        'icon' => 'menu-24',
        'iconPosition' => 'after',
    ]
])
```

Everything within the `args` array becomes a variable that you can reference within the same story blade file.

Update the component beneath the `@storybook` directive with:

```php
<x-button.primary
    :href="$href ?? null"
    :icon="$icon ?? null"
    :iconPosition="$iconPosition ?? null"
>
    {{ $label ?? null }}
</x-button.primary>
```

Blast will automatically regenerate the story and reload Storybook. The 'Controls' panel beneath your component will now contain text fields to edit all of the `args` and update the component view.

### Introducing `argTypes`

Being able to edit some of the fields with a text field is great, but using a text field for things like icons or the icon position is a bit of a pain so let's fix that by setting some `argTypes`.

`argTypes` allow us to further configure the control for each of the `args`. You can read more about `argTypes` and the available options in the [official Storybook docs](https://storybook.js.org/docs/react/essentials/controls).

Update the `@storybook` in your `primary.blade.php` to:

```php
@storybook([
    'args' => [
        'label' => 'Button',
        'href' => '#',
        'icon' => 'menu-24',
        'iconPosition' => 'after',
    ],
    'argTypes' => [
        'iconPosition' =>[
            'options' => [
                'before', 'after'
            ],
            'control' => [
                'type' => 'radio'
            ]
        ],
        'icon' =>[
            'options' => [
                'help-24', 'menu-24', 'plus-24'
            ],
            'control' => [
                'type' => 'select'

            ]
        ]
    ]
])
```

This will update the `iconPosition` fild to use `radio` buttons for the 'before' and 'after' options as well as updating the `icon` field to use a `select`. Much better!

### Rename the story

Blast uses the filename to create the story name. This could be fine for most of our components but sometimes we want to give our story a more descriptive name.

We can do that with the `name` parameter in our `@storybook` directive.

```php
@storybook([
    'name' => 'Button with Icon',
    ...
])
```

Storybook should now be showing the updated name in the sidebar.

### Setting a status

Blast ships with the [Status Addon](https://storybook.js.org/addons/@etchteam/storybook-addon-status) by Etch. This allows you to add custom status indicators to each component in the sidebar and above the story canvas area. The predefined statuses are `deprecated`, `wip`, `readyForQA` and `stable`. These can be edited/removed in `config/blast.php`. You can read more about customizing the statues in the [Blast docs](https://github.com/area17/blast#readme).

Let's flag that our button component has passed QA and is ready for use by setting the status to `stable`.

```php
@storybook([
    'status' => 'stable',
    ...
])
```

Storybook will now be showing a green status indicator in the sidebar and a green tag above the canvas area.

### Adding a Figma Design

Blast also installs the [design addon](https://storybook.js.org/addons/storybook-addon-designs) to allow you to embed Figma designs into your stories.

To embed a design, copy the URL from Figma or use the URL below and update your `@storybook` directive with the following:

```php
@storybook([
    'design' => 'https://www.figma.com/file/z3UTaD2Lt7d92J3n7fHKWI/Blast-Guide-Components?node-id=1%3A2',
    ...
])
```

Blast will regenerate the story and reload Storybook. The 'Design' tab beneath your component should now be showing the button design directly within Storybook.

### Using Presets

Sometimes it may be helpful for components to share data. You may have a number of different button components which all have the same props so instead of repeating all of the `args` and `argsTypes` data across all of those, and having to update all of them individually when, for example, you add an icon, we can manage this in a what Blast calls a 'preset'.

Blast allows you to create data presets to use in your stories. You can preset any of the options available in the `@storybook` directive and they will be merged with any `args` set directly in your story blade file. Presets allow you to write detailed stories faster and with more consistency.

You may have noticed a `data` directory was created when you initially launched Blast. Let's create a `button.php` file in the `data` directory which contains:

```php
<?php

return [
    'base' => [
        'status' => 'wip',
        'args' => [
            'label' => 'Button',
            'href' => '#',
            'icon' => 'menu-24',
            'iconPosition' => 'after',
        ],
        'argTypes' => [
            'iconPosition' =>[
                'options' => [
                    'before', 'after'
                ],
                'control' => [
                    'type' => 'radio'
                ]
            ],
            'icon' =>[
                'options' => [
                    'help-24', 'menu-24', 'plus-24'
                ],
                'control' => [
                    'type' => 'select'

                ]
            ]
        ]
    ]
];
```

This creates a preset of all of our button story config for us to use in our story blade files. All of the data in this preset can be overridden within your story. You could now go onto create 'secondary' and 'tertiary' button style without having to write any `args`.

To use the preset in your story update the `@storybook` directive to:

```php
@storybook([
    'preset' => 'button.base',
    'name' => 'Button with Icon',
    'status' => 'stable',
    'design' => 'https://www.figma.com/file/z3UTaD2Lt7d92J3n7fHKWI/Blast-Guide-Components?node-id=1%3A2',
])
```

Presets are referenced using dot notation starting with the filename followed by the indexes in the array within that file.

Our story should look the same as before, however, the code is a lot simpler. Note that the `status` is still showing 'stable' as it has overriden the `status` in the preset.

### Using `presetArgs`

Blast also allows you to reuse the `args` from the presets when rendering components inside other components. For example, we have a button box component which contains a title and two of our primary button components.

Create a story blade file for the button box component in `resources/views/stories/button-box/primary.blade.php` containing:

```php
@storybook([
    'args' => [
        'buttons' => [
            [
                'label' => 'Button',
                'href' => '#',
                'icon' => 'menu-24',
                'iconPosition' => 'after',
            ],
            [
                'label' => 'Button',
                'href' => '#',
                'icon' => 'menu-24',
                'iconPosition' => 'after',
            ]
        ]
    ]
])

<x-button-box.primary
    :title="$title ?? null"
    :buttons="$buttons ?? null"
/>
```

This works fine, however if we have a lot of duplicated code and should we ever change a prop on the button component, we would also need to update it here.

We can get around this by using `presetArgs`. `presetArgs` tells Blast to go to a `preset` and collect all of the `args` and associate them with the set key within the component's data. As of Blast 1.1.1, `presetArgs` can only be used within a `preset`.

Create a preset for the button box component in `resources/views/stories/data/button-box.php` containing:

```php
<?php

return [
    'primary' => [
        'presetArgs' => [
            'buttons' => ['button.base', 'button.base']
        ]
    ]
];
```

You can go into your `button-box/primary.blade.php` story file and remove the `buttons` args and set the `preset` to `button-box.primary`. This will create the `buttons` `args` data using the preset args we created earlier.

```php
@storybook([
    'preset' => 'button-box.primary'
])
```

These `presetArgs` can still be merged with other `args` data in the same way you would with a regular preset. Let's set a title for our button box outside of the preset:

```php
@storybook([
    'preset' => 'button-box.primary',
    'args' => [
        'title' => 'Button Box'
    ]
])

<x-button-box.primary
    :title="$title ?? null"
    :buttons="$buttons ?? null"
/>
```

### Documentation

Storybook automatically generates a 'Docs' tab alongside the canvas view of your component which details the component's props but Blast allows you to add to this by creating a `README.md` file alongside your component's story blade file.

Create a `README.md` in your `stories/button` directory and write some documentation for your new button component. When you save the file, Blast will regenerate the story and update Storybook. The `README` contents will now be visible in the 'Docs' tab of your story.

## Using the `DocsPage` Component

At AREA 17 we use a generic 'page' component to document more global parts of the design system like colors, grid system, typography, etc. Blast ships with a basic `DocsPage` component to allow you to do the same.

We'll use one to create an introduction page for the components in our guide.

Create `introduction.blade.php` in the root of your `stories` directory and add the following:

```php
@storybook([
    'layout' => 'fullscreen'
])

<x-docs-page
    title="Blast 🚀"
    label="About"
    description="Storybook for Laravel Blade"
>

{!! Str::markdown("# Introduction

This is the `DocsPage` component. You can put whatever you like into the main slot and it will render in the center column of the page. It also has 3 props - `title`, `label` and `description` - to fill out the content in the component header.

Be sure to set `layout` to `fullscreen` so it all renders correctly in the Storybook UI.
") !!}

</x-docs-page>

```

This will create a new story containing a fullscreen 'page' layout. You can use the `title`, `label` and `description` props to update the header content, and the component's main slot to update the body content.

## Generating a Static Storybook app with Blast

Everything we've just created is working great in dev but now we want to build a static version of our Storybook app to deploy on our server. We can do this by running:

```bash
php artisan blast:publish
```

This task runs [Storybook's `build-storybook` command](https://storybook.js.org/docs/react/workflows/publish-storybook) and publishes the generated storybook app to your public folder to allow it to be deployed alongside your application.

## Automated Accessibility Testing

Blast uses the [Storybook Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) to automatically test your components from within Storybook using [Axe](https://www.deque.com/axe/). It lists passed, failing and incomplete tests and allows you to highlight the elements in your components relating to each test as well as a full description of the test as well as reasons why it failed and the standard the test falls under.

## Customization

Storybook's UI looks great out of the box but sometimes we want to add our own branding to it. Blast allows you to complete control over the Storybook UI via the `storybook_theme` option in `config/blast.php`. You can read more about the theming options in the [official Storybook documentation](https://storybook.js.org/docs/react/configure/theming).

## Conclusion

There we have it. We have created our first component stories in Blast, customized our Storybook UI and published a static Storybook application to our Laravel app.

We are constantly working on improvements and new features for Blast and please swing by [our Github](https://github.com/area17/blast) with any ideas or PRs!