Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update CSF docs to clarify how naming works #9040

Merged
merged 1 commit into from
Dec 3, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 43 additions & 18 deletions docs/src/pages/formats/component-story-format/index.md
Original file line number Diff line number Diff line change
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 @@ -65,12 +88,12 @@ it('should format CSF exports with sensible defaults', () => {
});
```

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

You should use the `story.name` option in the following cases:

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 is useful for integration with third party tools.
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 @@ -80,27 +103,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$/`