Component Story Format (CSF)

Source file extensions: .stories.(js|jsx|ts|tsx)

Storybook’s Component Story Format (CSF) is the recommended way to write stories since Storybook 5.2.

In CSF, stories and component metadata are defined as ES Modules. Every component story file consists of a required default export and one or more named exports.

Components.studio supports Storybook 6.0 improvements.

Stories

Stories are named exports returning a function.

export const BasicButton = () => story;

The rendering of story depends on his type.

See our Open-Source universal-story-renderer for more details.

String

export const BasicButton = () => '<button>Basic</button>';

Element

var element = document.createElement('button');
element.appendChild(document.createTextNode('Click Me!'));
export const BasicButton = () => element;

lit-html

import { html } from 'lit-html';
import './my-button.js';

const name = 'World';
export const BasicButton = () => html`<button>Hello ${name}</button>`;

uhtml

import { html } from 'uhtml';
import './my-button.js';

const name = 'World';
export const BasicButton = () => html`<button>Hello ${name}</button>`;

lighterhtml

import { html } from 'lighterhtml';
import './my-button.js';

const name = 'World';
export const BasicButton = () => html`<button>Hello ${name}</button>`;

Omi (JSX)

/** @jsx h */
import './index.js';
import { h } from 'omi';

export const story1 = () => <my-counter></my-counter>;

Stencil (JSX)

/* @jsx h */
import { h } from '@stencil/core';
import './my-counter.tsx';

export const story1 = () => <my-counter></my-counter>;

Preact (JSX)

/** @jsx h */
import { h } from 'preact';
import MyCounter from './index.js';

export const story1 = () => <MyCounter></MyCounter>;

React (JSX)

import React from 'react';
import MyCounter from './index.js';

export const story1 = () => <MyCounter></MyCounter>;

Riot

import Counter from './index.riot';

export const story1 = () => Counter;

export const story2 = () => ({
Component: Counter,
props: {
count: 5,
},
});

Sinuous

import { html } from 'sinuous';
import MyCounter from './index.js';

export const story1 = () => html`<div><${MyCounter}></${MyCounter}></div>`;

Solid (JSX)

import MyCounter from './index.js';

export const story1 = () => MyCounter;
export const jsx = () => () => <MyCounter />; // Double function

Svelte

import Counter from './index.svelte';

export const story1 = () => Counter;

export const story2 = () => ({
Component: Counter,
props: {
count: 5,
},
});

Vue 3

import MyCounter from './index.vue';

export const story1 = () => ({
components: { MyCounter },
template: '<my-counter></my-counter>',
});

Parameters

Supported parameters are:

parameters: {
backgrounds: {
default: "light" | "dark",
},
layout: "centered" | "padded" | "fullscreen",
}

You can default the parameters of all stories in export default

export default {
parameters: {
backgrounds: {
default: 'dark',
},
layout: 'centered',
},
};

Or setup for a specific story

export const BasicButton = () => html`<button>Hello ${name}</button>`;
BasicButton.parameters = {
backgrounds: {
default: "dark",
},
layout: "centered",
}
};

Args

Args allows stories to receive dynamic data as input arguments.

const Template = (args) => <Button {...args} />;

export const Text = Template.bind({});
Text.args = { label: 'hello', background: '#ff0' };

export const Emoji = Template.bind({});
Emoji.args = { ...Text.args, label: '😀 😎 👍 💯' };

For more details see Introducing Storybook Args.

References

Quick example

index.stories.js

import './index.ts';
import { html } from 'lit-html';

export default {
parameters: {
backgrounds: {
default: 'dark',
},
layout: 'centered',
},
};

export const story1 = () => html` <name-tag>John Foo</name-tag> `;
export const story2 = () => html` <name-tag>John Bar</name-tag> `;
story2.parameters = { backgrounds: { default: 'light' } };