Using Storybook and Drupal Together

October 11, 2024

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 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 %}

8. Compile your Story:

ddev drush storybook:generate-stories stories/card/card.stories.twig

9. 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.