packagek-kinzal/storybook-php

A Storybook framework addon for developing and previewing PHP components as stories

Documents 8§

storybook-phpREADME.md
Security PolicySECURITY.md
Framework Optionsdocs/framework-options.md
Getting Starteddocs/getting-started.md
PHP Project Setupdocs/php-project-setup.md
Rendering Modeldocs/rendering-model.md
Testing and Typesdocs/testing-and-types.md
Type Mappingdocs/type-mapping.md

README§

storybook-php

MIT License npm version docs

A Storybook framework addon for developing and previewing PHP components as stories.

Supported Versions

  • PHP 8.0-8.5
  • Storybook 10.x
  • Vite 5.x-8.x
  • Node.js 20.19+

Quick Start

.storybook/main.ts:

import type { StorybookConfig } from "storybook";

const config: StorybookConfig = {
  stories: ["../src/**/*.stories.ts"],
  framework: {
    name: "storybook-php",
    options: {},
  },
};

export default config;

src/Greeting.php:

<?php
class Greeting {
    public function __construct(private string $name, private string $greeting = 'Hello') {}

    public function render(): string {
        return "<h2>{$this->greeting}, {$this->name}!</h2>";
    }
}

src/Greeting.stories.ts:

import type { Meta, StoryObj } from "storybook-php";
import { Greeting } from "./Greeting.php@render";

const meta: Meta<typeof Greeting> = {
  component: Greeting,
  title: "Components/Greeting",
};

export default meta;
type Story = StoryObj<typeof Greeting>;

export const Default: Story = {
  args: { name: "World" },
};
npx storybook-php start

npx storybook-php

CommandDescription
npx storybook-php start [storybook opts]Start the Storybook dev server
npx storybook-php build [storybook opts]Build static Storybook output
npx storybook-php test [vitest opts]Run Storybook tests through vitest run
npx storybook-php typegen [dirs...] [--options-file path]Generate declaration files for PHP import paths

start and build accept the same options as the storybook CLI (e.g. -p 6006). test passes arguments through to vitest run.

typegen defaults to the src directory when no directories are specified. It writes declaration files next to the source import path, including exact-import outputs such as Button.php@render.d.ts. When defaultMethod resolves, the bare Button.php.d.ts output mirrors that callable; otherwise a bare import remains template-shaped.

If your type generation depends on defaultMethod or typeMap, pass them through --options-file because typegen does not read .storybook/main.ts. The options file can be JSON or a JS module and may also provide _configDir for relative path resolution.

For PHP-first repositories that do not want to add a local package.json, see PHP Project Setup for the npx-based setup.

Testing

npx --package=storybook-php --package=vitest \
    --package=@storybook/addon-vitest \
    --package=@vitest/browser-playwright \
    storybook-php test

Add @storybook/addon-vitest to .storybook/main.ts:

const config: StorybookConfig = {
  addons: ["@storybook/addon-vitest"],
  // ...
};

If your project does not define vitest.config.* and you do not pass --config, the bundled Vitest config is used automatically. To customize, create your own vitest.config.*.

Import Syntax

PHP components are imported with the ./File.php@method specifier. The @method suffix tells storybook-php which callable to invoke. Constructor parameters and method parameters are merged into the story's args.

PatternImport SyntaxArgs Source
Class instance method./File.php@renderConstructor params + method params
Static method./File.php@dangerMethod params only
Standalone function./file.php@funcNameFunction params
Invocable class./File.php@__invokeConstructor params + __invoke params
Enum method./File.php@swatch_case + method params
Template file./file.php (default import)Template variables from args
Mapped non-PHP import source./card.blade.phptypeMap.files decides the public API

Methods that use echo instead of returning a string are captured via output buffering automatically.

Non-PHP sources such as Blade, Twig, or Latte are supported through framework.options.typeMap.files. Those mappings can provide public args, redirect execution to a PHP file, select a callable, include extra files for analysis, and attach adapter middleware.

Configuration

Configure in .storybook/main.ts under framework.options:

OptionTypeDefaultDescription
bootstrapstringundefinedPath to a PHP file executed before each render (autoloader, config, etc.)
phpBinarystring'php'Path to the PHP binary
phpOptionsstring[][]CLI options prepended to PHP (e.g. ["-d", "memory_limit=512M"])
phpEnvRecord<string, string>undefinedEnvironment variables merged over process.env when spawning PHP
timeoutnumber5000Render timeout in milliseconds
defaultMethodstringundefinedMethod name used when @method is omitted from the import specifier
adapterstringundefinedPath to a PHP adapter file for custom output handling (e.g. Laravel Blade)
typeMapobjectundefinedFile mappings, callable overrides, and runtime type bindings

The adapter file must return middleware compatible with fn(array $context, callable $next): array|string

Relative option paths are resolved from Storybook's config directory. defaultMethod and typeMap also affect module resolution, TS plugin output, and typegen when you pass them through --options-file.

TypeScript Support

Add to tsconfig.json for type support on .php imports and IDE integration:

{
  "compilerOptions": {
    "types": ["storybook-php/client"],
    "plugins": [{ "name": "storybook-php/ts-plugin" }]
  }
}

This gives editor support for .php imports without requiring generated files.

To generate declaration files on disk:

npx storybook-php typegen

typegen writes both bare-import and exact-import declarations when they resolve:

  • Button.php.d.ts
  • Button.php@render.d.ts

For advanced setups, load defaultMethod and typeMap from a separate file:

npx storybook-php typegen --options-file storybook-php.config.mjs

Documentation

License

MIT