> For the complete documentation index, see [llms.txt](https://docs.varbase.vardot.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.varbase.vardot.com/developers/theme-development-with-varbase/integration-of-varbase-with-storybook.md).

# Integration of Varbase with Storybook

**Varbase** has been integrated with [**Storybook**](https://storybook.js.org/) to provide a listing of stories for [**Single Directory Components (SDC)**](https://www.drupal.org/docs/develop/theming-drupal/using-single-directory-components) components. This integration allows for easier development and testing of [**Varbase Components**](https://www.drupal.org/project/varbase_components).

> **Warning:** Not for production. Only use for development or staging environments.

## Prerequisites

Follow the Varbase installation guide to build and install Varbase with DDEV before initializing Storybook.

{% content-ref url="/pages/eeDkXcvNxcnMrfQlO9eq" %}
[Installing Varbase locally with DDEV](/developers/installing-varbase/installing-varbase-with-ddev.md)
{% endcontent-ref %}

## The `ddev storybook` command

Varbase ships a single DDEV command to manage Storybook. Run `ddev storybook help` to see everything it does (alias: `ddev sb`).

```bash
ddev storybook <command>
```

The `ddev storybook` command is a convenience wrapper. The underlying `yarn` scripts still work, so if you have **not** updated to the new command yet you can keep using the equivalents in the right column.

| Command                  | What it does                                                                                                      | `yarn` equivalent                                      |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `ddev storybook init`    | Full first-time setup (same as `ddev init-storybook`).                                                            | `ddev init-storybook`                                  |
| `ddev storybook enable`  | Turn **on** the development local services (CORS + Twig debug) so the `storybook.*` subdomain can render stories. | —                                                      |
| `ddev storybook disable` | Turn them **off** and keep them off across restarts.                                                              | —                                                      |
| `ddev storybook list`    | Print the Storybook URLs / domains to open.                                                                       | —                                                      |
| `ddev storybook status`  | Show module / dev-services / daemon / port / CORS health.                                                         | —                                                      |
| `ddev storybook stats`   | Show how many stories are served, grouped by component group.                                                     | —                                                      |
| `ddev storybook doctor`  | Diagnose common problems and print the exact command to fix each.                                                 | —                                                      |
| `ddev storybook gen`     | Regenerate `*.stories.json` from Twig.                                                                            | `ddev yarn storybook:gen` (or `storybook:gen-new`)     |
| `ddev storybook build`   | Build a static Storybook into `./storybook`.                                                                      | `ddev yarn storybook:build`                            |
| — (manual dev server)    | Run a foreground dev server on port `6006`.                                                                       | `ddev yarn storybook:dev` / `ddev yarn storybook:ddev` |
| — (free port 6006)       | Kill a running Storybook process.                                                                                 | `ddev yarn storybook:kill`                             |

> **Note:** The Storybook **dev server runs automatically** as a DDEV `web_extra_daemon` (see `web_extra_daemons` in `.ddev/config.yaml`). You do **not** need to start it by hand — after `ddev storybook init` it is already serving on port `6006` and on the Storybook subdomain. All `yarn` scripts are defined in `package.json` and can also be run on the host without DDEV (`yarn storybook:build`, `yarn storybook:dev`, …).

## Initialize Storybook for DDEV

### 1. Initialize Storybook for Varbase

```bash
ddev init-storybook
```

or

```bash
ddev storybook init
```

Either command runs the same full first-time setup, which:

* Installs Node.js dependencies via `yarn install`
* Enables the `storybook` Drupal module
* Grants `render storybook stories` permission to anonymous and authenticated users
* Copies `development.local.services.yml` to `web/sites/default/`
* Enables the development services include in `settings.ddev.php` / `settings.platformsh.php` (via `ddev storybook enable`)
* Configures the `storybook.<project>.ddev.site` subdomain (`additional_fqdns` + the Apache proxy)
* Writes `.env.storybook` with `STORYBOOK_SERVER_URL` and `STORYBOOK_SERVER_RENDER_URL` pointing at the active Drupal site URL, used by the Storybook dev server and middleware to reach Drupal

Have a look at the content of the [storybook](https://github.com/Vardot/varbase-project/blob/11.0.x/.ddev/commands/web/storybook) and [init-storybook](https://github.com/Vardot/varbase-project/blob/11.0.x/.ddev/commands/web/init-storybook) commands.

> **Tip:** If `init` changed the subdomain or routing, run `ddev restart` once to apply it.

### 2. Generate Stories

Generate all stories using either command:

```bash
ddev storybook gen
```

or

```bash
ddev yarn storybook:gen
```

Both run the Drush command:

```bash
ddev drush storybook:generate-all-stories --omit-server-url --force
```

To generate only new stories (without overwriting existing ones):

```bash
ddev yarn storybook:gen-new
```

### 3. Open Varbase Storybook

The dev server is already running (as a `web_extra_daemon`). Print the URLs:

```bash
ddev storybook list
```

```
Storybook URLs for this project:
   • Subdomain:     https://storybook.varbase.ddev.site/
   • Direct port:   https://varbase.ddev.site:6006/
   • Drupal render: https://varbase.ddev.site/storybook/stories/render
   403 stories currently served.
```

Open the **subdomain** URL in your browser. The `:6006` direct URL also works.

To check everything is healthy:

```bash
ddev storybook status
```

If a story fails to render (for example a CORS error in the browser console), run the doctor — it tells you exactly what to fix:

```bash
ddev storybook doctor
```

### 4. Restarting DDEV

Story rendering keeps working across `ddev stop` / `ddev start` / `ddev restart`. DDEV regenerates `settings.ddev.php` on every start, so a `post-start` hook re-applies the development services (CORS) include automatically by running `ddev storybook enable --boot`.

To turn Storybook's development services off for a while (and keep them off across restarts):

```bash
ddev storybook disable
```

Re-enable them with:

```bash
ddev storybook enable
```

### Starting the dev server manually

You normally never need this — the daemon already runs it. To run a fresh foreground dev server (for example to watch its log), use the yarn script:

```bash
ddev yarn storybook:ddev
```

This binds to `0.0.0.0` so the subdomain proxy can reach it. To free port `6006`:

```bash
ddev yarn storybook:kill
```

## How Storybook Connects to Drupal <a href="#how-storybook-connects-to-drupal" id="how-storybook-connects-to-drupal"></a>

Storybook runs on its own port (`6006`) but renders SDC components by calling the Drupal site. Two pieces glue this together:

### `.storybook/middleware.js` <a href="#storybook-middleware-js" id="storybook-middleware-js"></a>

An Express middleware that proxies Drupal static assets (CSS, JS, fonts, images) through the Storybook dev server. The Storybook iframe runs at `:6006`, but Drupal assets are served from a different origin (e.g. `:8443`); browsers block cross-origin sub-resources loaded via `innerHTML` because static files have no CORS headers. The middleware routes paths under `/themes/`, `/modules/`, `/core/`, `/libraries/`, `/sites/`, and `/storybook/` to the Drupal base URL read from `process.env.STORYBOOK_SERVER_URL` so the browser sees them as same-origin requests.

### `.storybook/preview.ts` `fetchStoryHtml` <a href="#storybook-preview-ts-fetchstoryhtml" id="storybook-preview-ts-fetchstoryhtml"></a>

Custom fetch function for `@storybook/server` that:

* Cleans up Drupal SDC params before sending — strips `undefined`/`null` values and converts bare `#` URI values to empty strings (Drupal SDC validation rejects both)
* In development, relies on `middleware.js` to proxy assets — no rewriting needed
* In production (static `storybook:build` export), rewrites relative root-relative `href`/`src`/`action` attributes to absolute Drupal URLs so assets load from the live Drupal server instead of 404-ing on the static host

## When Adding or Changing Stories

Run `ddev storybook gen` (or `ddev yarn storybook:gen`) whenever stories are added or changed to regenerate all stories.

## Manual Setup (Without DDEV Commands)

If you prefer to set up Storybook manually instead of using the `ddev storybook init` command:

### Enable the Storybook Module

Enable the `storybook` module through the site interface or with Drush:

```bash
drush pm:enable storybook
```

> **Warning:** The Storybook module should not be kept running on a production site.

### Grant Permissions

Navigate to `/admin/people/permissions/module/storybook` to grant the `Render storybook stories` permission, or use Drush:

```bash
drush role:perm:add anonymous 'render storybook stories'
drush role:perm:add authenticated 'render storybook stories'
```

> **Warning:** Give to trusted roles only; this permission has security implications. Allows a user to access the Twig Storybook endpoint to render a template with stories.

To revoke the permission later:

```bash
drush role:perm:remove anonymous 'render storybook stories'
drush role:perm:remove authenticated 'render storybook stories'
```

### Configure Development Services

Create or update the `development.local.services.yml` file in `web/sites/default/` with the following content:

```yaml
# Local development services.
#
# To activate this feature, follow the instructions at the top of the
# 'settings.platformsh.php' or 'settings.local.php' file, which sits next to this file.
parameters:
  twig.config:
    debug: true
    cache: false
  http.response.debug_cacheability_headers: true
  storybook.development: true
  cors.config:
    enabled: true
    # Specify allowed headers, like 'x-allowed-header'.
    allowedHeaders: ['*']
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    allowedMethods: ['*']
    # Configure requests allowed from specific origins. Do not include trailing
    # slashes with URLs.
    allowedOrigins: ['*']
    # Configure requests allowed from origins, matching against regex patterns.
    allowedOriginsPatterns: ['*']
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: false
    # Sets the Access-Control-Max-Age header.
    maxAge: false
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: true
services:
  cache.backend.null:
    class: Drupal\Core\Cache\NullBackendFactory
```

> **Warning:** Not recommended to keep `cors.config` with `enabled: true` in production environments. Keep all changes in the `development.local.services.yml` file.

### Include the Development Services File

Add the following to `settings.local.php` or `settings.ddev.php`:

```php
// Enable the development local services for Storybook.
$settings['container_yamls'][] = $app_root . '/' . $site_path . '/development.local.services.yml';
```

> **Note:** With DDEV, `settings.ddev.php` is regenerated on every start, which would drop this line. The `ddev storybook` command handles that for you by re-adding it from a `post-start` hook — prefer `ddev storybook enable` over editing `settings.ddev.php` by hand.

### Install Dependencies and Start

1. Run `yarn install` to install dependencies
2. Run `yarn storybook:gen` to generate all stories
3. Run `yarn storybook:dev` to start Storybook on port 6006

## Customizing Varbase Storybook for a Project

### Switching Between Themes

To showcase a custom cloned generated theme, uncomment and modify the following line in the `.storybook/preview.ts` file:

```typescript
// mytheme: {title: 'My Custom Theme for a Project'}
```

### Show Vartheme BS5 Components

By default, the `.storybook/main.ts` file includes components from Vartheme BS5:

```typescript
"../web/themes/contrib/vartheme_bs5/components/**/*.mdx",
"../web/themes/contrib/vartheme_bs5/components/**/*.stories.@(json)",
```

### Show Custom Theme Components

To include components from a custom cloned generated theme, uncomment and modify the following lines in the `.storybook/main.ts` file:

{% content-ref url="/pages/WGulY4r5D7l3lF271q4s" %}
[Creating Your Own Theme](/developers/theme-development-with-varbase/creating-your-own-theme.md)
{% endcontent-ref %}

```typescript
"../web/themes/custom/mytheme/components/**/*.mdx",
"../web/themes/custom/mytheme/components/**/*.stories.@(json)",
```

Ensure the path to the custom theme is correct. It should be located in `../web/themes/custom/`.

### Show Custom Module Components

To include components from a custom module, uncomment and modify the following lines in the `.storybook/main.ts` file:

```typescript
"../web/modules/custom/my_custom_module/components/**/*.mdx",
"../web/modules/custom/my_custom_module/components/**/*.stories.@(json)",
```

### Bootstrap Color Modes

Varbase Storybook supports Bootstrap 5.3+ color modes. Use the root attributes addon in the Storybook toolbar to switch between Light and Dark themes, as well as LTR and RTL text direction.

## Storybook Build

Build a static version of Storybook for demos, staging, or hosted development environments using either command:

```bash
ddev storybook build
```

or

```bash
ddev yarn storybook:build
```

> **Danger:** Not for production environments. Only for development, staging, or demo.

This outputs the built Storybook to the `storybook` directory. A subdomain can then point to this directory:

* `my-staging-site.com` points at the `web` directory (Varbase site)
* `storybook.my-staging-site.com` points at the `storybook` directory (Storybook)

## Run Varbase Storybook on UPSUN

For development, testing, or staging environments on Platform.sh:

> **Danger:** NOT for production environments.

### Select the Varbase Template

Use the TEMP development for [**Vardot/upsun-varbase11x00**](https://github.com/Vardot/upsun-varbase11x00) from the pre-existing code base template to start a project.

### Use Development Services

Add the following to `settings.platformsh.php`:

```php
// Enable the development local services for Storybook.
if (isset($platformsh->branch)) {
  if (!$platformsh->onProduction() || !$platformsh->onDedicated()) {
    $settings['container_yamls'][] = $app_root . '/' . $site_path . '/development.local.services.yml';
  }
}
```

After committing and starting the development environment, the Storybook link will be available at:

```
https://storybook.{default}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.varbase.vardot.com/developers/theme-development-with-varbase/integration-of-varbase-with-storybook.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
