Skip to content

Commit

Permalink
Update CSF docs to clarify how naming works (#9040)
Browse files Browse the repository at this point in the history
Update CSF docs to clarify how naming works
  • Loading branch information
shilman committed Jan 11, 2020
1 parent 5182155 commit 67609c0
Showing 1 changed file with 45 additions and 18 deletions.
63 changes: 45 additions & 18 deletions docs/src/pages/formats/component-story-format/index.md
Expand Up @@ -5,7 +5,7 @@ title: 'Component Story Format (CSF)'

Storybook's Component Story Format (CSF) is the recommended way to [write stories](../../basics/writing-stories/) since Storybook 5.2. [Read the announcement](https://medium.com/storybookjs/component-story-format-66f4c32366df) to learn more about how it came to be.

In CSF, stories and component metadata are defined as ES6 modules. Every Component story file consists of a required default export and one or more named exports.
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**.

CSF is supported in all frameworks except React Native, where you should use the [storiesOf API](../storiesof-api/) instead.

Expand All @@ -24,20 +24,43 @@ export default {
}
```

For more examples, see [writing stories](../../basics/writing-stories/)
For more examples, see [writing stories](../../basics/writing-stories/).

## Story exports
## Named story exports

By default every named export in the file represents a story function.
With CSF, every named export in the file represents a story function by default.

```jsx
import MyComponent from './MyComponent';

export default { ... }

export const Basic = () => <MyComponent />;
export const WithProp = () => <MyComponent prop="value" />;
```

The exported identifiers will be converted to "start case" using Lodash's [startCase](https://lodash.com/docs/#startCase) function. For example:

```
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'
```

It's recommended to start export names with a capital letter.

Story functions can be annotated with a `story` object to define story-level [decorators](../../basics/writing-stories/#decorators) and [parameters](../../basics/writing-stories/#parameters), and also to define the `name` of the story.

The `name` is useful if you want to use names with spaces, 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.
The `name` 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.

```js
export const simple = () => <MyComponent prop1={val1} />;
simple.story = {
name: 'default', // can't be used as a named export
```jsx
export const Simple = () => <MyComponent />;

Simple.story = {
name: 'So simple!',
decorators: [ ... ],
parameters: { ... }
};
Expand Down Expand Up @@ -69,10 +92,12 @@ it('should format CSF exports with sensible defaults', () => {
});
```

Therefore, you should specify `story.name` in the following cases:
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.

1. Want the name to show up in the Storybook UI in a way that's not possible with a named export, e.g. reserved keywords like "default", special characters like emoji, spacing/capitalization other than what's provided by `storyNameFromExport`
2. Want to preserve the Story ID independently from changing how it's displayed. Having stable Story ID's can be useful for integration with third party tools.
You should use the `story.name` option in the following cases:

1. You want the name to show up in the Storybook UI in a way that's not possible with a named export, e.g. reserved keywords like "default", special characters like emoji, spacing/capitalization other than what's provided by `storyNameFromExport`.
2. You want to preserve the Story ID independently from changing how it's displayed. Having stable Story ID's is useful for integration with third party tools.

## Non-story exports

Expand All @@ -82,27 +107,29 @@ To make this possible, you can use optional `includeStories` and `excludeStories

Consider the following story file:

```js
```jsx
import React from 'react';
import MyComponent from './MyComponent';
import someData from './data.json';

export default {
title: 'MyComponent',
component: MyComponent,
includeStories: ['simpleStory', 'complexStory']
includeStories: ['SimpleStory', 'ComplexStory']
}

export const simpleData = { foo: 1, bar: 'baz' };
export const complexData = { foo: 1, { bar: 'baz', baz: someData }};
export const simpleStory = () => <MyComponent data={simpleData} />;
export const complexStory = () => <MyComponent data={complexData} />;

export const SimpleStory = () => <MyComponent data={simpleData} />;
export const ComplexStory = () => <MyComponent data={complexData} />;
```

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.
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.

For this specific example the equivalent result can be achieved in a few ways depending on what's convenient:

- `includeStories: ['simpleStory', 'complexStory']`
- `includeStories: ['SimpleStory', 'ComplexStory']`
- `includeStories: /.*Story$/`
- `excludeStories: ['simpleData', 'complexData']`
- `excludeStories: /.*Data$/`

0 comments on commit 67609c0

Please sign in to comment.