Storybook HTML renderer that enables developing, documenting, and testing HTML UI components in isolation
npx @tessl/cli install tessl/npm-storybook--html@9.1.0Storybook HTML is a renderer specifically designed for developing, documenting, and testing HTML UI components in isolation within the Storybook environment. It provides a bridge between raw HTML/JavaScript components and Storybook's development ecosystem, enabling developers to create stories for vanilla HTML components without requiring a specific frontend framework.
npm install @storybook/htmlimport type { Meta, StoryObj, StoryFn, Decorator } from "@storybook/html";For CommonJS:
const { Meta, StoryObj, StoryFn, Decorator } = require("@storybook/html");For portable stories (testing and documentation):
import { setProjectAnnotations } from "@storybook/html";For advanced rendering capabilities:
import { render, renderToCanvas, parameters, argTypesEnhancers } from "@storybook/html";import type { Meta, StoryObj } from "@storybook/html";
// Define component metadata
const meta: Meta = {
title: "Example/Button",
parameters: {
layout: "centered",
},
argTypes: {
backgroundColor: { control: "color" },
label: { control: "text" },
size: {
control: { type: "select" },
options: ["small", "medium", "large"],
},
},
};
export default meta;
type Story = StoryObj;
// String template story
export const Primary: Story = {
args: {
label: "Button",
backgroundColor: "#007bff",
},
render: ({ label, backgroundColor, ...args }) => {
return `
<button style="background-color: ${backgroundColor}; padding: 10px 20px; border: none; border-radius: 4px; color: white;">
${label}
</button>
`;
},
};
// Function-based story
export const Interactive: Story = {
args: {
label: "Click Me",
},
render: ({ label, ...args }) => {
const button = document.createElement("button");
button.textContent = label;
button.addEventListener("click", () => alert("Button clicked!"));
return button;
},
};Storybook HTML is built around several key concepts:
{{arg}} placeholder syntaxCore types for defining HTML stories with proper TypeScript support and Storybook integration.
/**
* Metadata to configure the stories for a component.
*/
type Meta<TArgs = Args> = ComponentAnnotations<HtmlRenderer, TArgs>;
/**
* Story function that represents a CSFv2 component example.
*/
type StoryFn<TArgs = Args> = AnnotatedStoryFn<HtmlRenderer, TArgs>;
/**
* Story object that represents a CSFv3 component example.
*/
type StoryObj<TArgs = Args> = StoryAnnotations<HtmlRenderer, TArgs>;
/**
* Story decorator function type for HTML renderer.
*/
type Decorator<TArgs = StrictArgs> = DecoratorFunction<HtmlRenderer, TArgs>;
/**
* Story loader function type for HTML renderer.
*/
type Loader<TArgs = StrictArgs> = LoaderFunction<HtmlRenderer, TArgs>;
/**
* Story context type for HTML renderer.
*/
type StoryContext<TArgs = StrictArgs> = GenericStoryContext<HtmlRenderer, TArgs>;
/**
* Project annotations type for HTML renderer.
*/
type Preview = ProjectAnnotations<HtmlRenderer>;Essential types for story arguments and configuration.
/**
* Generic arguments type for stories.
*/
type Args = Record<string, any>;
/**
* Argument type definitions for controls and documentation.
*/
type ArgTypes = Record<string, ArgTypeDef>;
/**
* Story parameters for configuration and metadata.
*/
type Parameters = Record<string, any>;
/**
* Strictly typed arguments for enhanced type safety.
*/
type StrictArgs = Record<string, any>;The core renderer interface that defines how HTML components are handled.
interface HtmlRenderer extends WebRenderer {
/**
* The component can be a string template, HTMLElement, or story function.
*/
component: string | HTMLElement | ArgsStoryFn<HtmlRenderer>;
/**
* The result returned by story functions - either HTML string or DOM node.
*/
storyResult: StoryFnHtmlReturnType;
}
/**
* Valid return types for HTML story functions.
*/
type StoryFnHtmlReturnType = string | Node;
/**
* Error display arguments for story rendering failures.
*/
interface ShowErrorArgs {
title: string;
description: string;
}Utilities for using stories outside of Storybook environment for testing and documentation.
/**
* Function that sets the globalConfig of your storybook for portable story usage.
* Should be run once to apply global configuration (decorators, parameters) to stories.
*
* @param projectAnnotations - Project configuration from .storybook/preview
* @returns Normalized project annotations for HTML renderer
*/
function setProjectAnnotations(
projectAnnotations:
| NamedOrDefaultProjectAnnotations<any>
| NamedOrDefaultProjectAnnotations<any>[]
): NormalizedProjectAnnotations<HtmlRenderer>;Essential rendering functions that power the HTML renderer's story rendering capabilities.
/**
* Core story rendering function that handles different component types.
* Processes string templates, HTMLElement instances, and function components.
*
* @param args - Story arguments passed to the component
* @param context - Story context containing metadata and configuration
* @returns Rendered HTML string or DOM node
*/
function render(args: Args, context: StoryContext): StoryFnHtmlReturnType;
/**
* Canvas rendering function that displays stories in the Storybook canvas.
* Handles DOM manipulation and lifecycle events for story display.
*
* @param renderContext - Rendering context with story function and callbacks
* @param canvasElement - Target DOM element for rendering the story
*/
function renderToCanvas(
renderContext: {
storyFn: () => StoryFnHtmlReturnType;
kind: string;
name: string;
showMain: () => void;
showError: (args: ShowErrorArgs) => void;
forceRemount: boolean;
},
canvasElement: HTMLElement
): void;For string-based components, the renderer supports template interpolation:
// Template with argument placeholders
export const TemplateExample: Story = {
args: {
title: "Hello World",
content: "This is dynamic content",
},
render: () => `
<div class="card">
<h2>{{title}}</h2>
<p>{{content}}</p>
</div>
`,
};For DOM-based components, arguments are automatically applied as attributes:
export const ElementExample: Story = {
args: {
"data-testid": "button",
class: "primary",
},
render: () => {
const button = document.createElement("button");
button.textContent = "Click me";
return button; // Arguments will be set as attributes
},
};For maximum flexibility, components can be functions that receive arguments and context:
type ComponentFunction = (args: Args, context: StoryContext) => StoryFnHtmlReturnType;
export const FunctionExample: Story = {
render: (args, context) => {
const { label, onClick } = args;
const button = document.createElement("button");
button.textContent = label;
button.addEventListener("click", onClick || (() => {}));
return button;
},
};Default configuration and enhancement utilities for the HTML renderer.
/**
* Default parameters object for HTML renderer configuration.
* Sets the renderer type to 'html' for proper Storybook integration.
*/
const parameters: {
renderer: 'html';
};
/**
* Array of argument type enhancers for improved story controls and documentation.
* Automatically enhances argument types for better Storybook integration.
*/
const argTypesEnhancers: ArgTypesEnhancer[];/**
* HTML renderer-specific parameters interface.
*/
interface Parameters {
renderer: 'html';
docs?: {
story: { inline: boolean };
source: {
type: SourceType.DYNAMIC;
language: 'html';
code: any;
excludeDecorators: any;
};
};
}
/**
* Extended story context for HTML renderer with HTML-specific parameters.
*/
type StoryContext = DefaultStoryContext<HtmlRenderer> & {
parameters: DefaultStoryContext<HtmlRenderer>['parameters'] & Parameters;
};