Using Storybook and Drupal Together
Storybook is a tool for creating and managing design systems and while it’s most commonly used with javascript frontends such as React, it can also be used with Twig and Drupal. Follow the steps below to get Storybook, Twig, Sass, and Drupal all working together nicely.
Prerequisites for Using Drupal and Storybook Together
- Make sure you have a reasonably up-to-date version of nodejs installed locally. We recommend using the nvm tool to manage node versions, but however you usually install node is fine.
- Have a local environment for your Drupal site running. Storybook connects to Drupal to render the individual components, so it’s a requirement that Drupal be running and accessible. This tutorial assumes you are using DDEV, but Lando will work as well. You’ll have to convert the DDEV commands to Lando commands but it should be pretty obvious what’s happening.
1. Install the Drupal Storybook Module
The Drupal Storybook module provides a bridge between Drupal and Storybook, allowing you to use Drupal to render Storybook-ready twig templates:
composer require drupal/storybook
ddev drush pm-install storybook
ddev drush role:perm:add anonymous 'render storybook stories'
ddev drush cr
Do not run the role:perm:add command above in production; you should disable the ‘render storybook stories’ permission in production
2. Configure Your Development Services
If using DDEV, add the following line to web/sites/default/settings.ddev.php:
$settings['container_yamls'][] = __DIR__ . '/development.services.yml';
Otherwise, add this to whichever settings.php file is in use on your site. It’s important that this file be referenced in the config.
Add the following to sites/default/development.services.yml under “parameters”:
storybook.development: true
cors.config:
enabled: true
allowedHeaders: ['*']
allowedMethods: ['*']
allowedOrigins: ['*']
exposedHeaders: false
maxAge: false
supportsCredentials: true
twig.config:
debug: true
auto_reload: true
cache: false
3. Enable Twig Debugging
ddev drush state:set twig_debug 1
ddev drush state:set twig_cache_disable 1
ddev drush state:set disable_rendered_output_cache_bins 1
4. Install Storybook
Run the following command from the root of your Drupal site:
npx storybook@latest init
When prompted:
- Choose “server” as the project type
- Choose “webpack5” as the builder
5. Change the Storybook Default Paths
This assumes that the web server root for your project (in other words: where Drupal’s index.php file lives) is web/
From the root of your project, open the newly created .storybook/main.js file and make the following changes:
Change FROM the following line:
stories: ["../stories/**/*.mdx", "../stories/**/*.stories.@(json|yaml|yml)"],
TO this line:
stories: ["../web/**/*.mdx", "../web/**/*.stories.@(json|yaml|yml)"]
6. Enable SCSS in Storybook
Install the webpack styling addon:
npx storybook@latest add @storybook/addon-styling-webpack
If you are not prompted to configure the addon, run the following command manually:
npx @storybook/auto-config styling
use the arrows to move down to “Sass” then hit the spacebar to actually chose it.
I also had to manually require the sass loader or I received the message “Cannot find module ‘sass’” when attempting to run Storybook:
npm install sass-loader sass webpack --save-dev
7. Set Up Global SCSS File in Storybook
Create the file web/stories/global/global.scss
(This file can actually be named whatever you want as long as you specify the correct path below)
Import the global style by adding the following line to the top of preview.js:
import '../web/stories/global/global.scss';
8. Create your First Story:
in web/stories/card/card.stories.twig:
{% stories card with { title: 'Morris/Components' } %}
{% story card with
{
name: 'Card',
args: {
classes: ['class-here'],
heading: 'Default heading',
body: 'Default Body',
link: {
'url': 'https://www.easternstandard.com',
'title': 'Eastern Standard',
'attributes': []
}
}
}
%}
<article{{ attributes.addClass(classes).addClass('card') }}>
{% block content %}
{% if heading %}
<h3 class="card-heading">
{{ heading }}
</h3>
{% endif %}
{{ body }}
{% if link.url %}
<span class="card-link">
<a href="{{ link.url }}">{{ link.title }}</a>
</span>
{% endif %}
{% endblock content %}
</article>
{% endstory %}
{% endstories %}
9. Compile Your Story:
ddev drush storybook:generate-stories stories/card/card.stories.twig
10. Run Storybook:
npm run storybook
You should be able to browse to the “card” story and see your markup. You can incorporate this story into your Drupal templates; read more at the official Drupal Storybook documentation.
Failed to Fetch Error Using the Drupal Storybook Module
If you’re getting “failed to fetch”, your CORS settings above are probably not being respected. Make sure your development.services.yml is being loaded by your configuration and that you’ve added the config above. To debug the failed to fetch, inspect the source in Storybook, open the iframe URL in a new window, refresh, and check the network tab.