Getting Started with Blast – Storybook for Laravel Blade

mrtimbrook

Tim Brook

Posted on October 18, 2021

Getting Started with Blast – Storybook for Laravel Blade

In this guide we'll show you how to set up a component library within your Laravel app using Blast.

First of all, what is Blast?

At AREA 17, we've been using Storybook for many years with both Vue and React and we love it, but our core technology is Laravel, 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, 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.

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:

composer require area17/blast
Enter fullscreen mode Exit fullscreen mode

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

Creating Stories

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

php artisan blast:launch
Enter fullscreen mode Exit fullscreen mode

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.

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
Enter fullscreen mode Exit fullscreen mode

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:

<x-button.primary>
    Primary Button
</x-button.primary>
Enter fullscreen mode Exit fullscreen mode

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.

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

@storybook([
    'args' => [
        'label' => 'Button',
        'href' => '#',
        'icon' => 'menu-24',
        'iconPosition' => 'after',
    ]
])
Enter fullscreen mode Exit fullscreen mode

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:

<x-button.primary
    :href="$href ?? null"
    :icon="$icon ?? null"
    :iconPosition="$iconPosition ?? null"
>
    {{ $label ?? null }}
</x-button.primary>
Enter fullscreen mode Exit fullscreen mode

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.

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

@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'

            ]
        ]
    ]
])
Enter fullscreen mode Exit fullscreen mode

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.

@storybook([
    'name' => 'Button with Icon',
    ...
])
Enter fullscreen mode Exit fullscreen mode

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

Setting a status

Blast ships with the Status Addon 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.

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

@storybook([
    'status' => 'stable',
    ...
])
Enter fullscreen mode Exit fullscreen mode

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 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:

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

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

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'

                ]
            ]
        ]
    ]
];
Enter fullscreen mode Exit fullscreen mode

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:

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

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:

@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"
/>
Enter fullscreen mode Exit fullscreen mode

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

return [
    'primary' => [
        'presetArgs' => [
            'buttons' => ['button.base', 'button.base']
        ]
    ]
];
Enter fullscreen mode Exit fullscreen mode

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.

@storybook([
    'preset' => 'button-box.primary'
])
Enter fullscreen mode Exit fullscreen mode

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:

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

<x-button-box.primary
    :title="$title ?? null"
    :buttons="$buttons ?? null"
/>
Enter fullscreen mode Exit fullscreen mode

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:

@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>

Enter fullscreen mode Exit fullscreen mode

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:

php artisan blast:publish
Enter fullscreen mode Exit fullscreen mode

This task runs Storybook's build-storybook command 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 to automatically test your components from within Storybook using 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.

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 with any ideas or PRs!

💖 💪 🙅 🚩
mrtimbrook
Tim Brook

Posted on October 18, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related