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
This will:
- Create a
stories
and adata
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 theblast: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
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
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>
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',
]
])
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>
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'
]
]
]
])
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',
...
])
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',
...
])
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',
...
])
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'
]
]
]
]
];
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',
])
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"
/>
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']
]
]
];
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'
])
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"
/>
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>
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
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!
Top comments (3)
I get an error like this, when I run
php artisan blast:launch
and enter the storybook's localhost, please provide a complete tutorial on js configuration and config, I have followed the one on the github github.com/area17/blast, but still getting this.fyi: I see this library defaults to using tailwind?
I use boostrap and sass to customize it
my setup
laravel : 8.0
module: webpack mix
If you are willing to help and provide information I really appreciate it.
Sorry I'm only just seeing this now. This error means that you either don't have any stories defined or blast cannot find them. You can run
php artisan blast:demo
to create an example component and story file to give an idea of where files need to go.There's no js configuration required, blast handles that for you. It only mentioned that as it is standard Storybook error.
Tailwind is only used by blast for the documentation pages, you are free to use whatever you need in your application.
What is the minimum version of Laravel required to use Blast?