diff --git a/docs/api/addons-api.md b/docs/api/addons-api.md
index 7db6a5636f02..26b927881e67 100644
--- a/docs/api/addons-api.md
+++ b/docs/api/addons-api.md
@@ -6,9 +6,15 @@ title: 'Addons API'
This is the core addon API. This is how to get the addon API:
-```jsx
-import { addons } from '@storybook/addons';
-```
+
+
+
+
+
### addons.getChannel()
@@ -21,14 +27,15 @@ It has a NodeJS [EventEmitter](https://nodejs.org/api/events.html) compatible AP
This method allows you to register an addon and get the storybook API. You can do this only in the Manager App.
See how we can use this:
-```js
-// my-addon/register.js
+
-import { addons } from '@storybook/addons';
+
-// Register the addon with a unique name.
-addons.register('my-organisation/my-addon', (api) => {});
-```
+
Now you'll get an instance to our StorybookAPI. See the [api docs](#storybook-api) for Storybook API regarding using that.
@@ -37,25 +44,15 @@ Now you'll get an instance to our StorybookAPI. See the [api docs](#storybook-ap
This method allows you to add a panel to Storybook. (Storybook's Action Logger is a panel). You can do this only in the Manager App.
See how you can use this method:
-```js
-// my-addon/register.js
+
-import { addons, types } from '@storybook/addons';
-import { AddonPanel } from '@storybook/components';
+
-const MyPanel = () =>
This is a panel.
;
-
-// give a unique name for the panel
-addons.add('my-organisation/my-addon/panel', {
- title: 'My Addon',
- type: types.PANEL,
- render: ({ active, key }) => (
-
-
-
- ),
-});
-```
+
The render function is called with `active` and `key`.
@@ -67,23 +64,15 @@ As you can see, you can set any React Component as the panel. Currently, it's on
The `makeDecorator` API can be used to create decorators in the style of the official addons. Use it like so:
-```js
-// my-addon/register.js
-
-import { makeDecorator } from '@storybook/addons';
+
-export makeDecorator({
- name: 'withSomething',
- parameterName: 'something',
- wrapper: (storyFn, context, { parameters }) => {
- // Do something with `parameters`, which are set via { something: ... }
+
- // Note you may alter the story output if you like, although generally that's
- // not advised
- return storyFn(context);
- }
-})
-```
+
The options to `makeDecorator` are:
@@ -107,13 +96,15 @@ Writing addons can be simplified a lot by using these Storybook hooks:
### useStorybookState
-```js
-export const Panel = () => {
- const state = useStorybookState();
+
- return
do something with storybook's state
;
-};
-```
+
+
+
Allows full access to the entire storybook state.
Your component will re-render whenever the storybook state changes.
@@ -122,15 +113,15 @@ If you use this, remember your component wil be re-rendered a lot, and you may n
### useStorybookApi
-```js
-// my-addon/register.js
+
-export const Panel = () => {
- const state = useStorybookApi();
+
- return
do something with storybook's api
;
-};
-```
+
Allows full access to the storybook API.
@@ -138,22 +129,15 @@ Detail on the storybook api are further down.
### useChannel
-```js
-// my-addon/register.js
+
-import { STORY_CHANGED } from '@storybook/core-events';
-export const Panel = () => {
- const emit = useChannel({
- STORY_CHANGED: (...args) => console.log(...args),
- });
+
- return (
-
- );
-};
-```
+
Allows for both setting subscriptions to events and getting the emitter for emitting custom event unto the channel.
@@ -161,20 +145,15 @@ The messages can be listened for on both the iframe and the manager side.
### useAddonState
-```js
-// my-addon/register.js
-
-export const Panel = () => {
- const [state, setState] = useAddonState('my/addon-id', 'initial state');
+
- return ;
-};
-export const Tool = () => {
- const [state, setState] = useAddonState('my/addon-id', 'initial state');
+
- return ;
-};
-```
+
Extremely useful for addons that need to persist some state.
@@ -186,20 +165,15 @@ With this hook they can all get access to the same bit of state which is persist
### useParameter
-```js
-// my-addon/register.js
+
-export const Panel = () => {
- const value = useParameter('parameter-key', 'default value');
+
- return (
-
- for the currently selected story, the parameter for "parameter-key" is:
- {value}
-
- );
-};
-```
+
This hook gets you the current story's parameter.
@@ -222,51 +196,55 @@ With this method, you can select a story via an API. This method accepts two par
Let's say you've got a story like this:
-```js
-// Heading.story.js
-export default {
- title: 'heading',
-};
+
-export const withText = () =>
Hello world
;
-```
+
+
+
This is how you can select the above story:
-```js
-// my-addon/register.js
+
+
+
-addons.register('my-organisation/my-addon', (api) => {
- api.selectStory('heading', 'withText');
-});
-```
+
### api.selectInCurrentKind()
Same as `selectStory`, but accepts a story inside current kind as the only parameter:
-```js
-// my-addon/register.js
+
-addons.register('my-organisation/my-addon', (api) => {
- api.selectInCurrentKind('withText');
-});
-```
+
+
+
### api.setQueryParams()
This method allows you to set query string parameters. You can use that as temporary storage for addons. Here's how you set query params.
-```js
-// my-addon/register.js
+
+
+
-addons.register('my-organisation/my-addon', (api) => {
- api.setQueryParams({
- abc: 'this is abc',
- bbc: 'this is bbc',
- });
-});
-```
+
@@ -274,49 +252,54 @@ If you need to remove a query param, use `null` for that. For an example, let's
-```js
-// my-addon/register.js
+
-addons.register('my-organisation/my-addon', (api) => {
- api.setQueryParams({
- bbc: null,
- });
-});
-```
+
+
+
### api.getQueryParam()
This method allows you to get a query param set by above API `setQueryParams`. For example, let's say we need to get the bbc query param. Then this how we do it:
-```jsx
-addons.register('my-organisation/my-addon', (api) => {
- api.getQueryParam('bbc');
-});
-```
+
+
+
+
+
### api.getUrlState(overrideParams)
This method allows you to get application url state with some changed params. For example, if you want to get a link to a particular story:
-```js
-// my-addon/register.js
+
+
+
-addons.register('my-organisation/my-addon', (api) => {
- const href = api.getUrlState({
- selectedKind: 'kind',
- selectedStory: 'story',
- }).url;
-});
-```
+
### api.on(eventName, fn)
This method allows you to register a handler function which will be called whenever the user navigates between stories.
-```js
-// my-addon/register.js
+
+
+
-addons.register('my-organisation/my-addon', (api) => {
- api.on('some-event', (eventData) => console.log(eventData));
-});
-```
+
diff --git a/docs/api/addons.md b/docs/api/addons.md
index 491c2dae0d50..9a9f4d4bb6d6 100644
--- a/docs/api/addons.md
+++ b/docs/api/addons.md
@@ -35,21 +35,15 @@ Let’s write a simple addon for Storybook which:
Let’s start by writing a story for our addon that exposes a custom parameter. The idea is that our addon will show this parameter in the addon panel.
-```js
-// Button.story.js
-
-import React from 'react';
-import Button from './Button';
-export default {
- title: 'Button',
- parameters: {
- myAddon: {
- data: 'this data is passed to the addon',
- },
- },
-};
-export const Basic = () => ;
-```
+
+
+
+
+
Because we added the story at the component level, the `myAddon` parameter is associated with all stories defined in the file.
@@ -57,29 +51,15 @@ Because we added the story at the component level, the `myAddon` parameter is as
Now let’s add a panel to Storybook in a file called `register.js`, which is the entry point for addons to register themselves.
-```js
-// .storybook/register.js
-
-import React from 'react';
-import { addons, types } from '@storybook/addons';
-import { AddonPanel } from '@storybook/components';
-
-const ADDON_ID = 'myaddon';
-const PANEL_ID = `${ADDON_ID}/panel`;
-
-const MyPanel = () =>
MyAddon
;
-addons.register(ADDON_ID, (api) => {
- addons.add(PANEL_ID, {
- type: types.PANEL,
- title: 'My Addon',
- render: ({ active, key }) => (
-
-
-
- ),
- });
-});
-```
+
+
+
+
+
This is boilerplate code for any addon that adds a panel to Storybook, and there’s really not much going on here. In this case, we’re just adding a static div that renders when the panel is selected in Storybook’s UI.
@@ -87,17 +67,15 @@ This is boilerplate code for any addon that adds a panel to Storybook, and there
Next, let’s replace the `MyPanel` component from above to show the parameter.
-```js
-// .storybook/register.js
+
-import { useParameter } from '@storybook/api';
-const PARAM_KEY = 'myAddon';
-const MyPanel = () => {
- const value = useParameter(PARAM_KEY, null);
- const item = value ? value.data : '';
- return
{item}
;
-};
-```
+
+
+
The new version is made smarter by `useParameter`, which is a [React hook](https://reactjs.org/docs/hooks-intro.html) that updates the parameter value and re-renders the panel every time the story changes.
@@ -109,13 +87,15 @@ Finally, let’s hook it all up. Addons are typically published as standalone pa
Update your [`.storybook/main.js`](../configure/overview.md#configure-story-rendering):
-```js
-// .storybook/main.js
+
-module.exports = {
- addons: ['path/to/register.js'],
-};
-```
+
+
+
The path can be an absolute location on your file system, or a path relative to your `.storybook` directory (e.g. `./my-addon/register.js` if you defined the addon inside your `.storybook` folder).
@@ -158,32 +138,27 @@ It’s possible to disable the addon panel for a particular story.
To make that possible, you need to pass the `paramKey` element when you register the panel:
-```js
-// .storybook/register.js
-
-addons.register(ADDON_ID, () => {
- addons.add(PANEL_ID, {
- type: types.PANEL,
- title: 'My Addon',
- render: () =>
Addon tab content
,
- paramKey: 'myAddon', // this element
- });
-});
-```
+
+
+
+
+
Then when adding a story, you can then pass a disabled parameter.
-```js
-// Button.story.js
+
-import React from 'react';
-export default {
- title: 'Button',
- parameters: {
- myAddon: { disable: true },
- },
-};
-```
+
+
+
### Styling your addon
@@ -241,25 +216,15 @@ Common uses for presets include:
Here’s an example of typical preset file:
-```js
-//preset.js
-export function config(entry = []) {
- return [...entry, require.resolve('./defaultParameters')];
-}
+
-export function managerEntries(entries) {
- return [...entries, require.resolve('./register')];
-}
+
-export const parameters = {
- backgrounds: {
- values: [
- { name: 'light', value: '#F8F8F8' },
- { name: 'dark', value: '#333333' },
- ],
- },
-};
-```
+
For more information on presets, see the [presets docs](./presets.md).
diff --git a/docs/api/argtypes.md b/docs/api/argtypes.md
index 7b6a019c4a9e..d5f2d457e412 100644
--- a/docs/api/argtypes.md
+++ b/docs/api/argtypes.md
@@ -36,23 +36,15 @@ To do so, Storybook uses various static analysis tools depending on your framewo
The format of the generated argType will look something like:
-```js
-const argTypes = {
- label: {
- name: 'label',
- type: { name: 'string', required: false },
- defaultValue: 'Hello',
- description: 'demo description',
- table: {
- type: { summary: 'string' },
- defaultValue: { summary: 'Hello' },
- }
- control: {
- type: 'text'
- }
- }
-}
-```
+
+
+
+
+
In this ArgTypes data structure, name, type, defaultValue, and description are standard fields in all ArgTypes (analogous to PropTypes in React). The table and control fields are addon-specific annotations. So, for example, the table annotation provides extra information to customize how label gets rendered, and the control annotation provides extra information for the control for editing the property.
@@ -69,43 +61,27 @@ In this ArgTypes data structure, name, type, defaultValue, and description are s
If you want more control over the props table or any other aspect of using argTypes, you can overwrite the generated argTypes for you component on a per-arg basis. For instance, with the above inferred argTypes and the following default export:
-```js
-export default {
- title: 'Button',
- component: Button,
- argTypes: {
- label: {
- description: 'overwritten description',
- table: {
- type: { summary: 'something short', detail: 'something really really long' },
- },
- control: {
- type: null,
- },
- },
- },
-};
-```
+
+
+
+
+
These values--description, table.type, and controls.type--get merged over the defaults that are extracted by Storybook. The final merged values would be:
-```js
-const argTypes = {
- label: {
- name: 'label',
- type: { name: 'string', required: false },
- defaultValue: 'Hello',
- description: 'overwritten description',
- table: {
- type: { summary: 'something short', detail: 'something really really long' },
- defaultValue: { summary: 'Hello' },
- }
- control: {
- type: null
- }
- }
-}
-```
+
+
+
+
+
In particular, this would render a row with a modified description, a type display with a dropdown that shows the detail, and no control.
@@ -113,9 +89,12 @@ In particular, this would render a row with a modified description, a type displ
If you want to access the argTypes of the current component inside an addon, you can use the `useArgTypes` hook from the `@storybook/api` package:
-```js
-import { useArgTypes } from '@storybook/api';
+
+
+
-// inside your panel
-const { argTypes } = useArgTypes();
-```
+
diff --git a/docs/api/csf.md b/docs/api/csf.md
index 4aca2a1afeaf..9878501e7b40 100644
--- a/docs/api/csf.md
+++ b/docs/api/csf.md
@@ -20,17 +20,15 @@ The default export defines metadata about your component, including the `compone
The `component` field is optional (but encouraged!), and is used by addons for automatic prop table generation and display of other component metadata. `title` should be unique, i.e. not re-used across files.
-```js
-// MyComponent.story.js
-import MyComponent from './MyComponent';
-
-export default {
- title: 'Path/To/MyComponent',
- component: MyComponent,
- decorators: [ ... ],
- parameters: { ... }
-}
-```
+
+
+
+
+
For more examples, see [writing stories](../writing-stories/introduction.md).
@@ -38,18 +36,15 @@ For more examples, see [writing stories](../writing-stories/introduction.md).
With CSF, every named export in the file represents a story function by default.
-```js
-// MyComponent.story.js
-import MyComponent from './MyComponent';
+
-export default {
- title: 'Path/To/MyComponent',
- component: MyComponent,
-};
+
-export const Basic = () => ;
-export const WithProp = () => ;
-```
+
The exported identifiers will be converted to "start case" using Lodash's [startCase](https://lodash.com/docs/#startCase) function. For example:
@@ -67,15 +62,15 @@ Story functions can be annotated with a few different fields to define story-lev
The `storyName` is useful if you want to use names with special characters, names that correspond to restricted keywords in Javascript, or names that collide with other variables in the file. If it's not specified, the export name will be used instead.
-```jsx
-// MyComponent.story.js
+
-export const Simple = () => ;
+
-Simple.storyName = 'So simple!';
-Simple.decorators = [ ... ];
-Simple.parameters = { ... };
-```
+
## Args story inputs
@@ -83,40 +78,51 @@ Starting in SB 6.0, stories accept named inputs called Args. Args are dynamic da
Consider Storybook’s ["Button" example](../writing-stories/introduction.md#defining-stories) of a text button that logs its click events:
-```js
-// Button.story.js
+
-import { action } from '@storybook/addon-actions';
-import { Button } from './Button';
+
-export default {
- title: 'Button',
- component: Button
-};
-export const Text = () => ;
-```
+
Now consider the same example, re-written with args:
-```js
-export const Text = ({ label, onClick }) => ;
-Text.args = {
- label: 'Hello',
- onClick: action('clicked'),
-};
-```
+
+
+
+
+
At first blush this might seem no better than the original example. However, if we add the [Docs addon](https://github.com/storybookjs/storybook/tree/master/addons/docs) and configure the [Actions addon](https://github.com/storybookjs/storybook/tree/master/addons/actions) appropriately, we can write:
-```js
-export const Text = ({ label, onClick }) => ;
-```
+
+
+
+
+
Or even more simply:
-```js
-export const Text = (args) => ;
-```
+
+
+
+
+
Not only are these versions shorter and easier to write than their no-args counterparts, but they are also more portable since the code doesn't depend on the actions addon specifically.
@@ -132,21 +138,15 @@ If you specify `story.name`, it will be used as the story display name in the UI
If you don't specify `story.name`, the named export will be used to generate the display name. Storybook passes the named export through a `storyNameFromExport` function, which is implemented with `lodash.startCase`:
-```js
-it('should format CSF exports with sensible defaults', () => {
- const testCases = {
- name: 'Name',
- someName: 'Some Name',
- someNAME: 'Some NAME',
- some_custom_NAME: 'Some Custom NAME',
- someName1234: 'Some Name 1234',
- someName1_2_3_4: 'Some Name 1 2 3 4',
- };
- Object.entries(testCases).forEach(([key, val]) => {
- expect(storyNameFromExport(key)).toBe(val);
- });
-});
-```
+
+
+
+
+
When you want to change the name of your story, just rename the CSF export. This will change the name of the story and also change the story's ID and URL.
@@ -163,25 +163,15 @@ To make this possible, you can use optional `includeStories` and `excludeStories
Consider the following story file:
-```js
-// MyComponent.story.js
-
-import React from 'react';
-import MyComponent from './MyComponent';
-import someData from './data.json';
-
-export default {
- title: 'MyComponent',
- component: MyComponent,
- includeStories: ['SimpleStory', 'ComplexStory']
-}
+
-export const simpleData = { foo: 1, bar: 'baz' };
-export const complexData = { foo: 1, { bar: 'baz', baz: someData }};
+
-export const SimpleStory = () => ;
-export const ComplexStory = () => ;
-```
+
When Storybook loads this file, it will see all the exports, but it will ignore the data exports and only treat `SimpleStory` and `ComplexStory` as stories.
diff --git a/docs/api/mdx.md b/docs/api/mdx.md
index 8acecd5136ad..927bf750c116 100644
--- a/docs/api/mdx.md
+++ b/docs/api/mdx.md
@@ -8,26 +8,15 @@ title: 'MDX Format'
Let's get started with an example that combines Markdown with a single story:
-```md
-import { Meta, Story, Canvas } from '@storybook/addon-docs/blocks';
-import { Checkbox } from './Checkbox';
+
-
-
-# Checkbox
-
-With `MDX` we can define a story for `Checkbox` right in the middle of our Markdown documentation.
+
-
-```
+
And here's how that's rendered in Storybook:
@@ -45,18 +34,15 @@ MDX-flavored [Component Story Format (CSF)](https://medium.com/storybookjs/compo
For example, here's the story from `Checkbox` example above, rewritten in CSF:
-```js
-import React from 'react';
-import { Checkbox } from './Checkbox';
-export default { title: "MDX/Checkbox" component: Checkbox };
-export const allCheckboxes = () => (
-
-);
-```
+
+
+
+
+
There's a one-to-one mapping from the code in `MDX` to `CSF`, which in turn directly corresponds to Storybook's internal `storiesOf` API. As a user, this means your existing Storybook knowledge should translate between the three. And technically, this means that the transformations that happen under the hood are simple and predictable.
@@ -64,52 +50,15 @@ There's a one-to-one mapping from the code in `MDX` to `CSF`, which in turn dire
Now let's look at a more realistic example to see a few more things we can do:
-```js
-import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
-
-import { Badge } from './Badge';
-import { Icon } from './Icon';
-
-
-
-# Badge
-
-Let's define a story for our `Badge` component:
-
-
- Positive
-
-
-We can drop it in a `Canvas` to get a code snippet:
-
-
-
-We can even preview multiple stories in a block. This
-gets rendered as a group, but defines individual stories
-with unique URLs and isolated snapshot tests.
-
-
-```
+
+
+
+
+
And here's how that gets rendered in Storybook:
@@ -119,15 +68,15 @@ And here's how that gets rendered in Storybook:
Suppose you have an existing story and want to embed it into your docs. Here's how to show a story with ID `some--id` (check the browser URL in Storybook v5+ to see a story's ID):
-```js
-import { Story } from "@storybook/addon-docs/blocks";
+
-# Some header
-
-And Markdown here
+
-
-```
+
You can also use the rest of the MDX features in conjunction with embedding. That includes source, preview, and prop tables.
@@ -135,27 +84,27 @@ You can also use the rest of the MDX features in conjunction with embedding. Tha
To add [decorators](../writing-docs/mdx.md#decorators-and-parameters) and [parameters](../writing-docs/mdx.md#decorators-and-parameters) in MDX:
-```js
-
+
+
-
-...
-
-```
+
In addition, global decorators work just like before, e.g. adding the following to your [`.storybook/preview.js`](../configure/overview.md#configure-story-rendering):
-```js
-// .storybook/preview.js
-import { addDecorator, addParameters } from '@storybook/react';
+
+
+
-addDecorator(...);
-addParameters({ ... });
-```
+
## Documentation-only MDX
diff --git a/docs/api/new-frameworks.md b/docs/api/new-frameworks.md
index ff2b22674f13..d130a3a04e39 100644
--- a/docs/api/new-frameworks.md
+++ b/docs/api/new-frameworks.md
@@ -43,12 +43,16 @@ These scripts pass an `options` object to `@storybook/core/server`, a library th
For example, here’s the boilerplate to start the dev server in `start-storybook`:
-```js
-import { buildDev } from '@storybook/core/server';
-import options from './options';
+
+
+
+
+
-buildDev(options);
-```
Thus the meat of adding framework presets is filling in that options object.
@@ -58,15 +62,15 @@ As described above, the server `options` object does the heavy lifting of config
Let’s look at the `@storybook/vue`’s options definition:
-```js
-const packageJson = require('../../package.json');
+
-export default {
- packageJson,
- framework: 'vue',
- frameworkPresets: [require.resolve('./framework-preset-vue.js')],
-};
-```
+
+
+
The value of the `framework` option (in this case ‘vue’) is something that gets passed to addons and allows them to do special case things for your framework.
@@ -82,16 +86,15 @@ Storybook stories are ES6 functions that return a “renderable object.”
Consider the following React story:
-```js
-// Button.story.js
-import { Button } from './Button';
-export default {
- title: 'Button',
- component: Button,
-};
+
-export const Sample = () => ;
-```
+
+
+
In this case, the renderable object is the React element, ``.
@@ -99,21 +102,15 @@ In most other frameworks, the renderable object is actually a plain javascript o
Consider the following hypothetical example:
-```js
-// Button.story.js
-
-import { Button } from './Button';
-export default {
- title: 'Button',
- component: Button,
-};
-export const Sample = () => ({
- template: '',
- data: {
- label: 'hello button',
- },
-});
-```
+
+
+
+
+
The design of this “renderable object” is framework-specific, and should ideally match the idioms of that framework.
@@ -121,34 +118,40 @@ The design of this “renderable object” is framework-specific, and should ide
The frameworks render function is the thing responsible for converting the renderable object into DOM nodes. This is typically of the form:
-```js
-const rootElement = document.getElementById('root');
+
-export default function renderMain({ storyFn }: RenderMainArgs) {
- const storyObj = storyFn();
- const html = fn(storyObj);
- rootElement.innerHTML = html;
-}
-```
+
+
+
### Package structure
On the client side, the key file is [`src/client/preview.js`](../configure/overview.md#configure-story-rendering):
-```js
-import { start } from '@storybook/core/client';
-import './globals';
-import render from './render';
-const api = start(render);
+
-// the boilerplate code
-```
+
+
+
The globals file typically sets up a single global variable that client-side code (such as addon-provided decorators) can refer to if needed to understand which framework its running in:
-```js
-import { window } from 'global';
-window.STORYBOOK_ENV = 'vue';
-```
+
+
+
+
+
The `start` function abstracts all of Storybook’s framework-independent client-side (browser) code, and it takes the render function we defined above. For examples of render functions, see [React](https://github.com/storybookjs/storybook/blob/next/app/react/src/client/preview/render.tsx), [Vue](https://github.com/storybookjs/storybook/blob/next/app/vue/src/client/preview/render.ts),[Angular](https://github.com/storybookjs/storybook/blob/next/app/angular/src/client/preview/render.ts) [Web-components](https://github.com/storybookjs/storybook/blob/next/app/web-components/src/client/preview/render.ts) in the Storybook monorepo.
diff --git a/docs/api/presets.md b/docs/api/presets.md
index 0433a9bec64d..26a6dbcfca90 100644
--- a/docs/api/presets.md
+++ b/docs/api/presets.md
@@ -18,11 +18,15 @@ yarn add @storybook/preset-typescript --dev
Then load it in the file `main.js` in your storybook folder (`.storybook` by default):
-```js
-module.exports = {
- addons: ['@storybook/preset-typescript'],
-};
-```
+
+
+
+
+
That's it. When Storybook starts up, it will configure itself for typescript without any further configuration. For more information, see the Typescript preset [README](https://github.com/storybookjs/presets/tree/master/packages/preset-typescript).
@@ -32,22 +36,15 @@ Presets can also take optional parameters. These can be used by the preset itsel
Consider this example:
-```js
-const path = require('path');
-module.exports = {
- addons: [
- {
- name: '@storybook/preset-typescript',
- options: {
- tsLoaderOptions: {
- configFile: path.resolve(__dirname, '../tsconfig.json'),
- },
- include: [path.resolve(__dirname)],
- },
- },
- ],
-};
-```
+
+
+
+
+
This configures the typescript loader using the app's `tsconfig.json` and also tells the typescript loader to only be applied to the current directory.
diff --git a/docs/api/writing-presets.md b/docs/api/writing-presets.md
index 94432354ef92..e7722679cac3 100644
--- a/docs/api/writing-presets.md
+++ b/docs/api/writing-presets.md
@@ -12,28 +12,15 @@ A preset is a set of hooks that is called by Storybook on initialization and can
Each configuration has a similar signature, accepting a base configuration object and options, as in this webpack example:
-```js
-//.storybook/main.js
-
-export async function webpack(baseConfig, options) {
- // Modify or replace config. Mutating the original reference object can cause unexpected bugs,
- // so in this example we replace.
- const { module = {} } = baseConfig;
-
- return {
- ...baseConfig,
- module: {
- ...module,
- rules: [
- ...(module.rules || []),
- {
- /* some new loader */
- },
- ],
- },
- };
-}
-```
+
+
+
+
+
### Babel
@@ -43,14 +30,15 @@ All functions take a [Babel configuration object](https://babeljs.io/docs/en/con
For example, Storybook's Mihtril support uses plugins internally and here's how it configures babel:
-```ts
-export function babelDefault(config: TransformOptions) {
- return {
- ...config,
- plugins: [...config.plugins, require.resolve('@babel/plugin-transform-react-jsx')],
- };
-}
-```
+
+
+
+
+
- `babel` is applied to the preview config, after it has been initialized by storybook
- `babelDefault` is applied to the preview config before any user presets have been applied
@@ -64,19 +52,15 @@ All functions take a [webpack4 configuration object](https://webpack.js.org/conf
For example, here is how Storybook automatically adopts `create-react-app`'s configuration if it's installed, where `applyCRAWebpackConfig` is a set of smart heuristics for modifying the input config.
-```js
-//.storybook/main.js
+
-export function webpackFinal(config, { configDir }) {
- if (!isReactScriptsInstalled()) {
- logger.info('=> Using base config because react-scripts is not installed.');
- return config;
- }
+
- logger.info('=> Loading create-react-app config.');
- return applyCRAWebpackConfig(config, configDir);
-}
-```
+
- `webpack` is applied to the preview config after it has been initialized by storybook
- `webpackFinal` is applied to the preview config after all user presets have been applied
@@ -88,19 +72,27 @@ The addon config `managerEntries` allows you to add addons to Storybook from wit
For example, the Storysource preset contains the following code:
-```js
-export function managerEntries(entry = []) {
- return [...entry, require.resolve('@storybook/addon-storysource/register')];
-}
-```
+
+
+
+
+
This is equivalent to [registering the addon manually](../get-started/browse-stories.md#addons) in [`main.js`](../configure/overview.md#configure-story-rendering):
-```js
-module.exports = {
- managerEntries: ['@storybook/addon-storysource/register'],
-};
-```
+
+
+
+
+
### Preview entries
@@ -135,11 +127,15 @@ This is equivalent to exporting the `backgrounds` parameter manually in `main.js
For users, the name `managerEntries` might be a bit too technical, so instead both users and preset-authors can simply use the property: `addons`:
-```js
-module.exports = {
- addons: ['@storybook/addon-storysource'],
-};
-```
+
+
+
+
+
The array of values can support both references to other presets and addons that should be included into the manager.
@@ -149,14 +145,15 @@ If this heuristic is incorrect for an addon you are using, you can explicitly op
Here's what it looks when combining presets and managerEntries in the addons property:
-```js
-module.exports = {
- addons: [
- '@storybook/addon-storysource/register', // a managerEntry
- '@storybook/addon-docs/preset', // a preset
- ],
-};
-```
+
+
+
+
+
### Entries
@@ -170,63 +167,41 @@ For example, some users want to configure the webpack for Storybook's UI and add
If it doesn't exist yet, create a file `.storybook/main.js`:
-```js
-//.storybook/main.js
+
-module.exports = {
- managerWebpack: async (config, options) => {
- // update config here
- return config;
- },
- managerBabel: async (config, options) => {
- // update config here
- return config;
- },
- webpackFinal: async (config, options) => {
- // change webpack config
- return config;
- },
- babel: async (config, options) => {
- return config;
- },
-};
-```
+
+
+
## Sharing advanced configuration
Change your `main.js` file to:
-```js
-//.storybook/main.js
+
-const path = require('path');
+
-module.exports = {
- addons: [path.resolve('./.storybook/my-preset')],
-};
-```
+
and extract the configuration to a new file `./storybook/my-preset.js`:
-```js
-// .storybook/my-preset.js
+
+
+
+
+
-module.exports = {
- managerWebpack: async (config, options) => {
- // update config here
- return config;
- },
- managerBabel: async (config, options) => {
- // update config here
- return config;
- },
- webpackFinal: async (config, options) => {
- return config;
- },
- babel: async (config, options) => {
- return config;
- },
-};
-```
Place your `my-preset.js` file wherever you want, if you want to share it far and wide you'll want to make it its own package.
diff --git a/docs/snippets/common/badge-story-starter-example.mdx.mdx b/docs/snippets/common/badge-story-starter-example.mdx.mdx
new file mode 100644
index 000000000000..4f24652e16b2
--- /dev/null
+++ b/docs/snippets/common/badge-story-starter-example.mdx.mdx
@@ -0,0 +1,49 @@
+```md
+
+
+
+import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
+
+import { Badge } from './Badge';
+import { Icon } from './Icon';
+
+
+
+# Badge
+
+Let's define a story for our `Badge` component:
+
+
+ Positive
+
+
+We can drop it in a `Canvas` to get a code snippet:
+
+
+
+We can even preview multiple stories in a block. This
+gets rendered as a group, but defines individual stories
+with unique URLs and isolated snapshot tests.
+
+
+```
\ No newline at end of file
diff --git a/docs/snippets/common/button-story-hypothetical-example.js.mdx b/docs/snippets/common/button-story-hypothetical-example.js.mdx
new file mode 100644
index 000000000000..8fd895f1d9b5
--- /dev/null
+++ b/docs/snippets/common/button-story-hypothetical-example.js.mdx
@@ -0,0 +1,15 @@
+```js
+// Button.stories.js
+
+import { Button } from './Button';
+export default {
+ title: 'Button',
+ component: Button,
+};
+export const Sample = () => ({
+ template: '',
+ data: {
+ label: 'hello button',
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/checkbox-story-starter-example.mdx.mdx b/docs/snippets/common/checkbox-story-starter-example.mdx.mdx
new file mode 100644
index 000000000000..290b3d4553cc
--- /dev/null
+++ b/docs/snippets/common/checkbox-story-starter-example.mdx.mdx
@@ -0,0 +1,24 @@
+```md
+
+
+
+
+import { Meta, Story, Canvas } from '@storybook/addon-docs/blocks';
+import { Checkbox } from './Checkbox';
+
+
+
+# Checkbox
+
+With `MDX` we can define a story for `Checkbox` right in the middle of our Markdown documentation.
+
+
+```
\ No newline at end of file
diff --git a/docs/snippets/common/my-component-story-mandatory-export.js.mdx b/docs/snippets/common/my-component-story-mandatory-export.js.mdx
new file mode 100644
index 000000000000..1361b35ca292
--- /dev/null
+++ b/docs/snippets/common/my-component-story-mandatory-export.js.mdx
@@ -0,0 +1,11 @@
+```js
+// MyComponent.story.js
+import MyComponent from './MyComponent';
+
+export default {
+ title: 'Path/To/MyComponent',
+ component: MyComponent,
+ decorators: [ ... ],
+ parameters: { ... }
+}
+```
\ No newline at end of file
diff --git a/docs/snippets/common/my-component-story-mdx-with-decorators-params.mdx.mdx b/docs/snippets/common/my-component-story-mdx-with-decorators-params.mdx.mdx
new file mode 100644
index 000000000000..117d810a7332
--- /dev/null
+++ b/docs/snippets/common/my-component-story-mdx-with-decorators-params.mdx.mdx
@@ -0,0 +1,14 @@
+```md
+
+
+
+
+
+
+...
+
+```
\ No newline at end of file
diff --git a/docs/snippets/common/my-component-story-with-storyname.js.mdx b/docs/snippets/common/my-component-story-with-storyname.js.mdx
new file mode 100644
index 000000000000..b495b9710bf6
--- /dev/null
+++ b/docs/snippets/common/my-component-story-with-storyname.js.mdx
@@ -0,0 +1,9 @@
+```js
+// MyComponent.story.js
+
+export const Simple = () => ;
+
+Simple.storyName = 'So simple!';
+Simple.decorators = [ ... ];
+Simple.parameters = { ... };
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addon-change-panel.js.mdx b/docs/snippets/common/storybook-addon-change-panel.js.mdx
new file mode 100644
index 000000000000..f53320c24ac3
--- /dev/null
+++ b/docs/snippets/common/storybook-addon-change-panel.js.mdx
@@ -0,0 +1,11 @@
+```js
+// .storybook/my-addon/register.js
+
+import { useParameter } from '@storybook/api';
+const PARAM_KEY = 'myAddon';
+const MyPanel = () => {
+ const value = useParameter(PARAM_KEY, null);
+ const item = value ? value.data : '';
+ return
{item}
;
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addon-disable-addon.js.mdx b/docs/snippets/common/storybook-addon-disable-addon.js.mdx
new file mode 100644
index 000000000000..243e9d625c38
--- /dev/null
+++ b/docs/snippets/common/storybook-addon-disable-addon.js.mdx
@@ -0,0 +1,12 @@
+```js
+// .storybook/my-addon/register.js
+
+addons.register(ADDON_ID, () => {
+ addons.add(PANEL_ID, {
+ type: types.PANEL,
+ title: 'My Addon',
+ render: () =>
Addon tab content
,
+ paramKey: 'myAddon', // this element
+ });
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addon-panel-initial.js.mdx b/docs/snippets/common/storybook-addon-panel-initial.js.mdx
new file mode 100644
index 000000000000..468cf9206d25
--- /dev/null
+++ b/docs/snippets/common/storybook-addon-panel-initial.js.mdx
@@ -0,0 +1,24 @@
+```js
+// .storybook/my-addon/register.js
+
+import React from 'react';
+import { addons, types } from '@storybook/addons';
+import { AddonPanel } from '@storybook/components';
+
+const ADDON_ID = 'myaddon';
+const PANEL_ID = `${ADDON_ID}/panel`;
+
+// give a unique name for the panel
+const MyPanel = () =>
MyAddon
;
+addons.register(ADDON_ID, (api) => {
+ addons.add(PANEL_ID, {
+ type: types.PANEL,
+ title: 'My Addon',
+ render: ({ active, key }) => (
+
+
+
+ ),
+ });
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addon-preset-example.js.mdx b/docs/snippets/common/storybook-addon-preset-example.js.mdx
new file mode 100644
index 000000000000..319f70fe3f54
--- /dev/null
+++ b/docs/snippets/common/storybook-addon-preset-example.js.mdx
@@ -0,0 +1,20 @@
+```js
+//.storybook/my-addon/preset.js
+
+export function config(entry = []) {
+ return [...entry, require.resolve('./defaultParameters')];
+}
+
+export function managerEntries(entries) {
+ return [...entries, require.resolve('./register')];
+}
+
+export const parameters = {
+ backgrounds: {
+ values: [
+ { name: 'light', value: '#F8F8F8' },
+ { name: 'dark', value: '#333333' },
+ ],
+ },
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx b/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx
new file mode 100644
index 000000000000..cee489e5a2f2
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx
@@ -0,0 +1,9 @@
+```js
+// .storybook/my-addon/register.js
+
+addons.register('my-organisation/my-addon', (api) => {
+ api.setQueryParams({
+ bbc: null,
+ });
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx b/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx
new file mode 100644
index 000000000000..b0b0c8b87ec9
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx
@@ -0,0 +1,7 @@
+```js
+// .storybook/my-addon/register.js
+
+addons.register('my-organisation/my-addon', (api) => {
+ api.getQueryParam('bbc');
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx b/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx
new file mode 100644
index 000000000000..f5b0d4af3beb
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx
@@ -0,0 +1,10 @@
+```js
+// .storybook/my-addon/register.js
+
+addons.register('my-organisation/my-addon', (api) => {
+ const href = api.getUrlState({
+ selectedKind: 'kind',
+ selectedStory: 'story',
+ }).url;
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-imports.js.mdx b/docs/snippets/common/storybook-addons-api-imports.js.mdx
new file mode 100644
index 000000000000..eb2af57b1a9a
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-imports.js.mdx
@@ -0,0 +1,5 @@
+```js
+// .storybook/my-addon/register.js
+
+import { addons } from '@storybook/addons';
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx b/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx
new file mode 100644
index 000000000000..2f69823954b9
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx
@@ -0,0 +1,18 @@
+```js
+// .storybook/my-addon/register.js
+
+import { makeDecorator } from '@storybook/addons';
+
+export makeDecorator({
+ name: 'withSomething',
+ parameterName: 'something',
+ wrapper: (storyFn, context, { parameters }) => {
+ // Do something with `parameters`, which are set via { something: ... }
+
+ // Note you may alter the story output if you like.
+ // Although generally that's not advised.
+
+ return storyFn(context);
+ }
+})
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-on.js.mdx b/docs/snippets/common/storybook-addons-api-on.js.mdx
new file mode 100644
index 000000000000..8bface5e84eb
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-on.js.mdx
@@ -0,0 +1,7 @@
+```js
+// storybook/my-addon/register.js
+
+addons.register('my-organisation/my-addon', (api) => {
+ api.on('some-event', (eventData) => console.log(eventData));
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-register.js.mdx b/docs/snippets/common/storybook-addons-api-register.js.mdx
new file mode 100644
index 000000000000..009b2ea7e660
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-register.js.mdx
@@ -0,0 +1,8 @@
+```js
+// .storybook/my-addon/register.js
+
+import { addons } from '@storybook/addons';
+
+// Register the addon with a unique name.
+addons.register('my-organisation/my-addon', (api) => {});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx b/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx
new file mode 100644
index 000000000000..a5209b66dd2b
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx
@@ -0,0 +1,7 @@
+```js
+// .storybook/my-addon/register.js
+
+addons.register('my-organisation/my-addon', (api) => {
+ api.selectInCurrentKind('Basic');
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-selectstory.js.mdx b/docs/snippets/common/storybook-addons-api-selectstory.js.mdx
new file mode 100644
index 000000000000..5985ea54286e
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-selectstory.js.mdx
@@ -0,0 +1,7 @@
+```js
+// .storybook/my-addon/register.js
+
+addons.register('my-organisation/my-addon', (api) => {
+ api.selectStory('Button', 'Basic');
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx b/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx
new file mode 100644
index 000000000000..a5b3a707f653
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx
@@ -0,0 +1,10 @@
+```js
+// .storybook/my-addon/register.js
+
+addons.register('my-organisation/my-addon', (api) => {
+ api.setQueryParams({
+ abc: 'this is abc',
+ bbc: 'this is bbc',
+ });
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx b/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx
new file mode 100644
index 000000000000..bc98bc6b1b9a
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx
@@ -0,0 +1,14 @@
+```js
+// .storybook/my-addon/register.js
+
+export const Panel = () => {
+ const [state, setState] = useAddonState('my/addon-id', 'initial state');
+
+ return ;
+};
+export const Tool = () => {
+ const [state, setState] = useAddonState('my/addon-id', 'initial state');
+
+ return ;
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-useapi.js.mdx b/docs/snippets/common/storybook-addons-api-useapi.js.mdx
new file mode 100644
index 000000000000..da49b6418916
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-useapi.js.mdx
@@ -0,0 +1,9 @@
+```js
+// .storybook/my-addon/register.js
+
+export const Panel = () => {
+ const state = useStorybookApi();
+
+ return
do something with storybook's api
;
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-usechannel.js.mdx b/docs/snippets/common/storybook-addons-api-usechannel.js.mdx
new file mode 100644
index 000000000000..b08320cdbe8b
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-usechannel.js.mdx
@@ -0,0 +1,16 @@
+```js
+// .storybook/my-addon/register.js
+
+import { STORY_CHANGED } from '@storybook/core-events';
+export const Panel = () => {
+ const emit = useChannel({
+ STORY_CHANGED: (...args) => console.log(...args),
+ });
+
+ return (
+
+ );
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-useparameter.js.mdx b/docs/snippets/common/storybook-addons-api-useparameter.js.mdx
new file mode 100644
index 000000000000..20aaf02af3f5
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-useparameter.js.mdx
@@ -0,0 +1,14 @@
+```js
+// .storybook/my-addon/register.js
+
+export const Panel = () => {
+ const value = useParameter('parameter-key', 'default value');
+
+ return (
+
+ for the currently selected story, the parameter for "parameter-key" is:
+ {value}
+
+ );
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx b/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx
new file mode 100644
index 000000000000..88d84c9e02c1
--- /dev/null
+++ b/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx
@@ -0,0 +1,9 @@
+```js
+// .storybook/my-addon/register.js
+
+export const Panel = () => {
+ const state = useStorybookState();
+
+ return
do something with storybook's state
;
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-argtypes-with-addon.js.mdx b/docs/snippets/common/storybook-argtypes-with-addon.js.mdx
new file mode 100644
index 000000000000..30ba78220b20
--- /dev/null
+++ b/docs/snippets/common/storybook-argtypes-with-addon.js.mdx
@@ -0,0 +1,8 @@
+```js
+// storybook/my-addon/register.js
+
+import { useArgTypes } from '@storybook/api';
+
+// inside your panel
+const { argTypes } = useArgTypes();
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-babel-configuration-example.ts.mdx b/docs/snippets/common/storybook-babel-configuration-example.ts.mdx
new file mode 100644
index 000000000000..8ce82c58d99f
--- /dev/null
+++ b/docs/snippets/common/storybook-babel-configuration-example.ts.mdx
@@ -0,0 +1,13 @@
+```ts
+// mithril/src/server/framework-preset-mithril.ts
+
+export function babelDefault(config: TransformOptions) {
+ return {
+ ...config,
+ plugins: [
+ ...config.plugins,
+ require.resolve('@babel/plugin-transform-react-jsx')
+ ],
+ };
+}
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-client-globals-example-file.ts.mdx b/docs/snippets/common/storybook-client-globals-example-file.ts.mdx
new file mode 100644
index 000000000000..96bd5bca622d
--- /dev/null
+++ b/docs/snippets/common/storybook-client-globals-example-file.ts.mdx
@@ -0,0 +1,6 @@
+```ts
+// vue/src/client/preview/globals.ts
+
+import { window } from 'global';
+window.STORYBOOK_ENV = 'vue';
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-client-preview.ts.mdx b/docs/snippets/common/storybook-client-preview.ts.mdx
new file mode 100644
index 000000000000..43b96cd58b55
--- /dev/null
+++ b/docs/snippets/common/storybook-client-preview.ts.mdx
@@ -0,0 +1,10 @@
+```ts
+// your-framework/src/client/preview/index.ts
+
+import { start } from '@storybook/core/client';
+import './globals';
+import render from './render';
+const api = start(render);
+
+// the boilerplate code
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-customize-argtypes.js.mdx b/docs/snippets/common/storybook-customize-argtypes.js.mdx
new file mode 100644
index 000000000000..fb5535b9e143
--- /dev/null
+++ b/docs/snippets/common/storybook-customize-argtypes.js.mdx
@@ -0,0 +1,22 @@
+```js
+// Button.stories.js
+
+export default {
+ title: 'Button',
+ component: Button,
+ argTypes: {
+ label: {
+ description: 'overwritten description',
+ table: {
+ type: {
+ summary: 'something short',
+ detail: 'something really really long'
+ },
+ },
+ control: {
+ type: null,
+ },
+ },
+ },
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-framework-render-function.js.mdx b/docs/snippets/common/storybook-framework-render-function.js.mdx
new file mode 100644
index 000000000000..3c5699a52202
--- /dev/null
+++ b/docs/snippets/common/storybook-framework-render-function.js.mdx
@@ -0,0 +1,9 @@
+```js
+const rootElement = document.getElementById('root');
+
+export default function renderMain({ storyFn }: RenderMainArgs) {
+ const storyObj = storyFn();
+ const html = fn(storyObj);
+ rootElement.innerHTML = html;
+}
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-generated-argtypes.js.mdx b/docs/snippets/common/storybook-generated-argtypes.js.mdx
new file mode 100644
index 000000000000..de4a45b8a2a0
--- /dev/null
+++ b/docs/snippets/common/storybook-generated-argtypes.js.mdx
@@ -0,0 +1,17 @@
+```js
+const argTypes = {
+ label: {
+ name: 'label',
+ type: { name: 'string', required: false },
+ defaultValue: 'Hello',
+ description: 'demo description',
+ table: {
+ type: { summary: 'string' },
+ defaultValue: { summary: 'Hello' },
+ }
+ control: {
+ type: 'text'
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-advanced-config-example.js.mdx b/docs/snippets/common/storybook-main-advanced-config-example.js.mdx
new file mode 100644
index 000000000000..abb0574521d1
--- /dev/null
+++ b/docs/snippets/common/storybook-main-advanced-config-example.js.mdx
@@ -0,0 +1,21 @@
+```js
+//.storybook/main.js
+
+module.exports = {
+ managerWebpack: async (config, options) => {
+ // update config here
+ return config;
+ },
+ managerBabel: async (config, options) => {
+ // update config here
+ return config;
+ },
+ webpackFinal: async (config, options) => {
+ // change webpack config
+ return config;
+ },
+ babel: async (config, options) => {
+ return config;
+ },
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-import-preset-config.js.mdx b/docs/snippets/common/storybook-main-import-preset-config.js.mdx
new file mode 100644
index 000000000000..3b9634cc4307
--- /dev/null
+++ b/docs/snippets/common/storybook-main-import-preset-config.js.mdx
@@ -0,0 +1,9 @@
+```js
+//.storybook/main.js
+
+const path = require('path');
+
+module.exports = {
+ addons: [path.resolve('./.storybook/my-preset')],
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-preset-config.js.mdx b/docs/snippets/common/storybook-main-preset-config.js.mdx
new file mode 100644
index 000000000000..2f664ed34969
--- /dev/null
+++ b/docs/snippets/common/storybook-main-preset-config.js.mdx
@@ -0,0 +1,7 @@
+```js
+// .storybook/main.js
+
+module.exports = {
+ addons: ['@storybook/preset-typescript'],
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-register-addon.js.mdx b/docs/snippets/common/storybook-main-register-addon.js.mdx
new file mode 100644
index 000000000000..0f587017ee85
--- /dev/null
+++ b/docs/snippets/common/storybook-main-register-addon.js.mdx
@@ -0,0 +1,7 @@
+```js
+// .storybook/main.js
+
+module.exports = {
+ addons: ['path/to/register.js'],
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-register-presets-managerentry.js.mdx b/docs/snippets/common/storybook-main-register-presets-managerentry.js.mdx
new file mode 100644
index 000000000000..7c9d1b254dff
--- /dev/null
+++ b/docs/snippets/common/storybook-main-register-presets-managerentry.js.mdx
@@ -0,0 +1,10 @@
+```js
+// storybook/main.js
+
+module.exports = {
+ addons: [
+ '@storybook/addon-storysource/register', // a managerEntry
+ '@storybook/addon-docs/preset', // a preset
+ ],
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-register-storysource-example.js.mdx b/docs/snippets/common/storybook-main-register-storysource-example.js.mdx
new file mode 100644
index 000000000000..f74a788eead5
--- /dev/null
+++ b/docs/snippets/common/storybook-main-register-storysource-example.js.mdx
@@ -0,0 +1,7 @@
+```js
+// .storybook/main.js
+
+module.exports = {
+ addons: ['@storybook/addon-storysource'],
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-use-manager-entries.js.mdx b/docs/snippets/common/storybook-main-use-manager-entries.js.mdx
new file mode 100644
index 000000000000..5bbaa228a809
--- /dev/null
+++ b/docs/snippets/common/storybook-main-use-manager-entries.js.mdx
@@ -0,0 +1,7 @@
+```js
+// .storybook/main.js
+
+module.exports = {
+ managerEntries: ['@storybook/addon-storysource/register'],
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-webpack-preset-config.js.mdx b/docs/snippets/common/storybook-main-webpack-preset-config.js.mdx
new file mode 100644
index 000000000000..842fbb99283a
--- /dev/null
+++ b/docs/snippets/common/storybook-main-webpack-preset-config.js.mdx
@@ -0,0 +1,23 @@
+```js
+//.storybook/main.js
+
+export async function webpack(baseConfig, options) {
+ //Modify or replace config.
+ //Mutating the original reference object can cause unexpected bugs,
+ //so in this example we replace.
+ const { module = {} } = baseConfig;
+
+ return {
+ ...baseConfig,
+ module: {
+ ...module,
+ rules: [
+ ...(module.rules || []),
+ {
+ /* some new loader */
+ },
+ ],
+ },
+ };
+}
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-main-webpackfinal-example.js.mdx b/docs/snippets/common/storybook-main-webpackfinal-example.js.mdx
new file mode 100644
index 000000000000..35ebd7e6c52b
--- /dev/null
+++ b/docs/snippets/common/storybook-main-webpackfinal-example.js.mdx
@@ -0,0 +1,13 @@
+```js
+//.storybook/main.js
+
+export function webpackFinal(config, { configDir }) {
+ if (!isReactScriptsInstalled()) {
+ logger.info('=> Using base config because react-scripts is not installed.');
+ return config;
+ }
+
+ logger.info('=> Loading create-react-app config.');
+ return applyCRAWebpackConfig(config, configDir);
+}
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-merged-argtypes.js.mdx b/docs/snippets/common/storybook-merged-argtypes.js.mdx
new file mode 100644
index 000000000000..7eafe85038a6
--- /dev/null
+++ b/docs/snippets/common/storybook-merged-argtypes.js.mdx
@@ -0,0 +1,20 @@
+```js
+const argTypes = {
+ label: {
+ name: 'label',
+ type: { name: 'string', required: false },
+ defaultValue: 'Hello',
+ description: 'overwritten description',
+ table: {
+ type: {
+ summary: 'something short',
+ detail: 'something really really long'
+ },
+ defaultValue: { summary: 'Hello' },
+ }
+ control: {
+ type: null
+ }
+ }
+}
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-preset-configuration.js.mdx b/docs/snippets/common/storybook-preset-configuration.js.mdx
new file mode 100644
index 000000000000..95a0e70a0fc8
--- /dev/null
+++ b/docs/snippets/common/storybook-preset-configuration.js.mdx
@@ -0,0 +1,18 @@
+```js
+// .storybook/typescript-preset.js
+
+const path = require('path');
+module.exports = {
+ addons: [
+ {
+ name: '@storybook/preset-typescript',
+ options: {
+ tsLoaderOptions: {
+ configFile: path.resolve(__dirname, '../tsconfig.json'),
+ },
+ include: [path.resolve(__dirname)],
+ },
+ },
+ ],
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-preset-full-config-object.js.mdx b/docs/snippets/common/storybook-preset-full-config-object.js.mdx
new file mode 100644
index 000000000000..743778aa7110
--- /dev/null
+++ b/docs/snippets/common/storybook-preset-full-config-object.js.mdx
@@ -0,0 +1,20 @@
+```js
+// .storybook/my-preset.js
+
+module.exports = {
+ managerWebpack: async (config, options) => {
+ // update config here
+ return config;
+ },
+ managerBabel: async (config, options) => {
+ // update config here
+ return config;
+ },
+ webpackFinal: async (config, options) => {
+ return config;
+ },
+ babel: async (config, options) => {
+ return config;
+ },
+};
+````
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-preview-decorator-params-example.js.mdx b/docs/snippets/common/storybook-preview-decorator-params-example.js.mdx
new file mode 100644
index 000000000000..dd311391623d
--- /dev/null
+++ b/docs/snippets/common/storybook-preview-decorator-params-example.js.mdx
@@ -0,0 +1,7 @@
+```js
+// .storybook/preview.js
+import { addDecorator, addParameters } from '@storybook/react';
+
+addDecorator(...);
+addParameters({ ... });
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-server-options.ts.mdx b/docs/snippets/common/storybook-server-options.ts.mdx
new file mode 100644
index 000000000000..7fff894c8b4f
--- /dev/null
+++ b/docs/snippets/common/storybook-server-options.ts.mdx
@@ -0,0 +1,11 @@
+```ts
+// vue/src/server/options.ts
+
+const packageJson = require('../../package.json');
+
+export default {
+ packageJson,
+ framework: 'vue',
+ frameworkPresets: [require.resolve('./framework-preset-vue.js')],
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-start-dev-server.ts.mdx b/docs/snippets/common/storybook-start-dev-server.ts.mdx
new file mode 100644
index 000000000000..c5d23259897f
--- /dev/null
+++ b/docs/snippets/common/storybook-start-dev-server.ts.mdx
@@ -0,0 +1,8 @@
+```ts
+// your-framework/src/server/index.ts
+
+import { buildDev } from '@storybook/core/server';
+import options from './options';
+
+buildDev(options);
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-storysource-manager-entries.js.mdx b/docs/snippets/common/storybook-storysource-manager-entries.js.mdx
new file mode 100644
index 000000000000..5e792ec1d298
--- /dev/null
+++ b/docs/snippets/common/storybook-storysource-manager-entries.js.mdx
@@ -0,0 +1,7 @@
+```js
+// storysource/preset.js
+
+export function managerEntries(entry = []) {
+ return [...entry, require.resolve('@storybook/addon-storysource/register')];
+}
+```
\ No newline at end of file
diff --git a/docs/snippets/common/storybook-test-with-storyname.js.mdx b/docs/snippets/common/storybook-test-with-storyname.js.mdx
new file mode 100644
index 000000000000..d86c32b9ab4e
--- /dev/null
+++ b/docs/snippets/common/storybook-test-with-storyname.js.mdx
@@ -0,0 +1,17 @@
+```js
+// MyComponent-test.js
+
+it('should format CSF exports with sensible defaults', () => {
+ const testCases = {
+ name: 'Name',
+ someName: 'Some Name',
+ someNAME: 'Some NAME',
+ some_custom_NAME: 'Some Custom NAME',
+ someName1234: 'Some Name 1234',
+ someName1_2_3_4: 'Some Name 1 2 3 4',
+ };
+ Object.entries(testCases).forEach(([key, val]) => {
+ expect(storyNameFromExport(key)).toBe(val);
+ });
+});
+```
\ No newline at end of file
diff --git a/docs/snippets/react/button-story-click-handler-args.js.mdx b/docs/snippets/react/button-story-click-handler-args.js.mdx
new file mode 100644
index 000000000000..e9ceab29ccca
--- /dev/null
+++ b/docs/snippets/react/button-story-click-handler-args.js.mdx
@@ -0,0 +1,9 @@
+```js
+// Button.stories.js
+
+export const Text = ({ label, onClick }) => ;
+Text.args = {
+ label: 'Hello',
+ onClick: action('clicked'),
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/react/button-story-click-handler-simple-docs.js.mdx b/docs/snippets/react/button-story-click-handler-simple-docs.js.mdx
new file mode 100644
index 000000000000..c44f8ca4c626
--- /dev/null
+++ b/docs/snippets/react/button-story-click-handler-simple-docs.js.mdx
@@ -0,0 +1,5 @@
+```js
+// Button.stories.js
+
+export const Text = ({ label, onClick }) => ;
+```
\ No newline at end of file
diff --git a/docs/snippets/react/button-story-click-handler-simplificated.js.mdx b/docs/snippets/react/button-story-click-handler-simplificated.js.mdx
new file mode 100644
index 000000000000..5ca379db5365
--- /dev/null
+++ b/docs/snippets/react/button-story-click-handler-simplificated.js.mdx
@@ -0,0 +1,5 @@
+```js
+// Button.stories.js
+
+export const Text = (args) => ;
+```
\ No newline at end of file
diff --git a/docs/snippets/react/button-story-click-handler.js.mdx b/docs/snippets/react/button-story-click-handler.js.mdx
new file mode 100644
index 000000000000..d2c4996d27a3
--- /dev/null
+++ b/docs/snippets/react/button-story-click-handler.js.mdx
@@ -0,0 +1,12 @@
+```js
+// Button.stories.js
+
+import { action } from '@storybook/addon-actions';
+import { Button } from './Button';
+
+export default {
+ title: 'Button',
+ component: Button
+};
+export const Text = () => ;
+```
\ No newline at end of file
diff --git a/docs/snippets/react/button-story-disable-addon.js.mdx b/docs/snippets/react/button-story-disable-addon.js.mdx
new file mode 100644
index 000000000000..f19e5403584c
--- /dev/null
+++ b/docs/snippets/react/button-story-disable-addon.js.mdx
@@ -0,0 +1,11 @@
+```js
+// Button.story.js
+
+import React from 'react';
+export default {
+ title: 'Button',
+ parameters: {
+ myAddon: { disable: true },
+ },
+};
+```
\ No newline at end of file
diff --git a/docs/snippets/react/button-story-with-addon-example.js.mdx b/docs/snippets/react/button-story-with-addon-example.js.mdx
new file mode 100644
index 000000000000..4ab44f8c3e49
--- /dev/null
+++ b/docs/snippets/react/button-story-with-addon-example.js.mdx
@@ -0,0 +1,15 @@
+```js
+// Button.stories.js
+
+import React from 'react';
+import Button from './Button';
+export default {
+ title: 'Button',
+ parameters: {
+ myAddon: {
+ data: 'this data is passed to the addon',
+ },
+ },
+};
+export const Basic = () => ;
+```
\ No newline at end of file
diff --git a/docs/snippets/react/button-story-with-sample.js.mdx b/docs/snippets/react/button-story-with-sample.js.mdx
new file mode 100644
index 000000000000..39d8ccee8f86
--- /dev/null
+++ b/docs/snippets/react/button-story-with-sample.js.mdx
@@ -0,0 +1,11 @@
+```js
+// Button.stories.js
+
+import { Button } from './Button';
+export default {
+ title: 'Button',
+ component: Button,
+};
+
+export const Sample = () => ;
+```
\ No newline at end of file
diff --git a/docs/snippets/react/checkbox-story-csf.js.mdx b/docs/snippets/react/checkbox-story-csf.js.mdx
new file mode 100644
index 000000000000..8f0c17d41b2d
--- /dev/null
+++ b/docs/snippets/react/checkbox-story-csf.js.mdx
@@ -0,0 +1,17 @@
+```js
+// Checkbox.stories.js
+
+import React from 'react';
+import { Checkbox } from './Checkbox';
+export default {
+ title: "MDX/Checkbox",
+ component: Checkbox
+};
+export const allCheckboxes = () => (
+
+);
+```
\ No newline at end of file
diff --git a/docs/snippets/react/my-component-story-basic-and-props.js.mdx b/docs/snippets/react/my-component-story-basic-and-props.js.mdx
new file mode 100644
index 000000000000..cbf004e2aaa3
--- /dev/null
+++ b/docs/snippets/react/my-component-story-basic-and-props.js.mdx
@@ -0,0 +1,14 @@
+```js
+// MyComponent.stories.js
+
+import MyComponent from './MyComponent';
+
+export default {
+ title: 'Path/To/MyComponent',
+ component: MyComponent,
+};
+
+export const Basic = () => ;
+export const WithProp = () => ;
+
+```
\ No newline at end of file
diff --git a/docs/snippets/react/my-component-story-with-nonstory.js.mdx b/docs/snippets/react/my-component-story-with-nonstory.js.mdx
new file mode 100644
index 000000000000..e1aae4f692fe
--- /dev/null
+++ b/docs/snippets/react/my-component-story-with-nonstory.js.mdx
@@ -0,0 +1,19 @@
+```js
+// MyComponent.story.js
+
+import React from 'react';
+import MyComponent from './MyComponent';
+import someData from './data.json';
+
+export default {
+ title: 'MyComponent',
+ component: MyComponent,
+ includeStories: ['SimpleStory', 'ComplexStory']
+}
+
+export const simpleData = { foo: 1, bar: 'baz' };
+export const complexData = { foo: 1, { bar: 'baz', baz: someData }};
+
+export const SimpleStory = () => ;
+export const ComplexStory = () => ;
+```
\ No newline at end of file