Skip to content

Commit

Permalink
Merge pull request #26544 from storybookjs/update-docs-multiple-compo…
Browse files Browse the repository at this point in the history
…nents

Docs: Update multiple components guidance
(cherry picked from commit 6b773a6)
  • Loading branch information
kylegach authored and storybook-bot committed Apr 5, 2024
1 parent 064dc95 commit 6af31bf
Show file tree
Hide file tree
Showing 14 changed files with 30 additions and 88 deletions.
5 changes: 0 additions & 5 deletions docs/snippets/angular/list-story-reuse-data.ts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ const meta: Meta<List> = {
export default meta;
type Story = StoryObj<List>;

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems: Story = {
args: {
Selected: Selected.args.isSelected,
Expand Down
9 changes: 0 additions & 9 deletions docs/snippets/html/list-story-reuse-data.js.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,9 @@ import { createListItem } from './ListItem';
import { Selected, Unselected } from './ListItem.stories';

export default {
/* 👇 The title prop is optional.
* See https://storybook.js.org/docs/configure/#configure-story-loading
* to learn how to generate automatic titles
*/
title: 'List',
};

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems = {
render: (args) => {
const list = createList(args);
Expand Down
9 changes: 0 additions & 9 deletions docs/snippets/html/list-story-reuse-data.ts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,12 @@ import { createListItem } from './ListItem';
import { Selected, Unselected } from './ListItem.stories';

const meta: Meta<ListArgs> = {
/* 👇 The title prop is optional.
* See https://storybook.js.org/docs/configure/#configure-story-loading
* to learn how to generate automatic titles
*/
title: 'List',
};

export default meta;
type Story = StoryObj<ListArgs>;

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems: Story = {
render: (args) => {
const list = createList(args);
Expand Down
6 changes: 0 additions & 6 deletions docs/snippets/react/list-story-reuse-data.js.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ export default {
component: List,
};

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/

export const ManyItems = {
render: (args) => (
<List {...args}>
Expand Down
5 changes: 0 additions & 5 deletions docs/snippets/react/list-story-reuse-data.ts-4-9.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems: Story = {
render: (args) => (
<List {...args}>
Expand Down
5 changes: 0 additions & 5 deletions docs/snippets/react/list-story-reuse-data.ts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ const meta: Meta<typeof List> = {
export default meta;
type Story = StoryObj<typeof List>;

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems: Story = {
render: (args) => (
<List {...args}>
Expand Down
6 changes: 0 additions & 6 deletions docs/snippets/solid/list-story-reuse-data.js.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ export default {
component: List,
};

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/

export const ManyItems = {
render: (args) => (
<List {...args}>
Expand Down
5 changes: 0 additions & 5 deletions docs/snippets/solid/list-story-reuse-data.ts-4-9.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems: Story = {
render: (args) => (
<List {...args}>
Expand Down
5 changes: 0 additions & 5 deletions docs/snippets/solid/list-story-reuse-data.ts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ const meta: Meta<typeof List> = {
export default meta;
type Story = StoryObj<typeof List>;

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems: Story = {
render: (args) => (
<List {...args}>
Expand Down
5 changes: 0 additions & 5 deletions docs/snippets/vue/list-story-reuse-data.3.js.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ export default {
component: List,
};

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems = {
render: (args) => ({
components: { List, ListItem },
Expand Down
5 changes: 0 additions & 5 deletions docs/snippets/vue/list-story-reuse-data.3.ts-4-9.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems: Story = {
render: (args) => ({
components: { List, ListItem },
Expand Down
5 changes: 0 additions & 5 deletions docs/snippets/vue/list-story-reuse-data.3.ts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ const meta: Meta<typeof List> = {
export default meta;
type Story = StoryObj<typeof List>;

/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const ManyItems: Story = {
render: (args) => ({
components: { List, ListItem },
Expand Down
4 changes: 2 additions & 2 deletions docs/writing-stories/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ Decorators [can be more complex](./decorators.md#context-for-mocking) and are of

## Stories for two or more components

When building design systems or component libraries, you may have two or more components created to work together. For instance, if you have a parent `List` component, it may require child `ListItem` components.
Sometimes you may have two or more components created to work together. For instance, if you have a parent `List` component, it may require child `ListItem` components.

<!-- prettier-ignore-start -->

Expand Down Expand Up @@ -405,7 +405,7 @@ In such cases, it makes sense to render a different function for each story:

<!-- prettier-ignore-end -->

You can also reuse stories from the child `ListItem` in your `List` component. That’s easier to maintain because you don’t have to keep the identical story definitions updated in multiple places.
You can also reuse _story data_ from the child `ListItem` in your `List` component. That’s easier to maintain because you don’t have to update it in multiple places.

<!-- prettier-ignore-start -->

Expand Down
44 changes: 28 additions & 16 deletions docs/writing-stories/stories-for-multiple-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
title: 'Stories for multiple components'
---

It's useful to write stories that [render two or more components](../writing-stories/index.md#stories-for-two-or-more-components) at once if those components are designed to work together. For example, `ButtonGroups`, `Lists`, and `Page` components. Here's an example with `List` and `ListItem` components:
It's useful to write stories that [render two or more components](./index.md#stories-for-two-or-more-components) at once if those components are designed to work together. For example, `ButtonGroup`, `List`, and `Page` components.

## Subcomponents

When the components you're documenting have a parent-child relationship, you can use the `subcomponents` property to document them together. This is especially useful when the child component is not meant to be used on its own, but only as part of the parent component.

Here's an example with `List` and `ListItem` components:

<!-- prettier-ignore-start -->

Expand Down Expand Up @@ -33,32 +39,36 @@ Subcomponents are only intended for documentation purposes and have some limitat

Let's talk about some techniques you can use to mitigate the above, which are especially useful in more complicated situations.

## Reusing subcomponent stories
## Reusing story definitions

The simplest change we can make to the above is to reuse the stories of the `ListItem` in the `List`:
We can also reduce repetition in our stories by reusing story definitions. Here, we can reuse the `ListItem` stories' args in the story for `List`:

<!-- prettier-ignore-start -->

<CodeSnippets
paths={[
'react/list-story-unchecked.js.mdx',
'react/list-story-unchecked.ts.mdx',
'vue/list-story-unchecked.3.js.mdx',
'vue/list-story-unchecked.3.ts.mdx',
'angular/list-story-unchecked.ts.mdx',
'web-components/list-story-unchecked.js.mdx',
'web-components/list-story-unchecked.ts.mdx',
'solid/list-story-unchecked.js.mdx',
'solid/list-story-unchecked.ts.mdx',
'react/list-story-reuse-data.js.mdx',
'react/list-story-reuse-data.ts.mdx',
'angular/list-story-reuse-data.ts.mdx',
'vue/list-story-reuse-data.3.js.mdx',
'vue/list-story-reuse-data.3.ts.mdx',
'web-components/list-story-reuse-data.js.mdx',
'web-components/list-story-reuse-data.ts.mdx',
'html/list-story-reuse-data.js.mdx',
'html/list-story-reuse-data.ts.mdx',
'solid/list-story-reuse-data.js.mdx',
'solid/list-story-reuse-data.ts.mdx',
]}
usesCsf3
csf2Path="writing-stories/stories-for-multiple-components#snippet-list-story-unchecked"
csf2Path="writing-stories/#snippet-list-story-reuse-data"
/>

<!-- prettier-ignore-end -->

By rendering the `Unchecked` story with its args, we are able to reuse the input data from the `ListItem` stories in the `List`.

<If renderer="react">

However, we still aren’t using args to control the `ListItem` stories, which means we cannot change them with controls and we cannot reuse them in other, more complex component stories.

## Using children as an arg
Expand All @@ -82,19 +92,21 @@ Now that `children` is an arg, we can potentially reuse it in another story.

However, there are some caveats when using this approach that you should be aware of.

The `children` `args` as any other arg needs to be JSON serializable. It means that you should:
The `children` arg, just like all args, needs to be JSON serializable. To avoid errors with your Storybook, you should:

- Avoid using empty values
- Use [mapping](../essentials/controls.md#dealing-with-complex-values) if you want to adjust the value with [controls](../essentials/controls.md)
- Use caution with components that include third party libraries

As they could lead into errors with your Storybook.

<Callout variant="info">

We're currently working on improving the overall experience for the children arg and allow you to edit children arg in a control and allow you to use other types of components in the near future. But for now you need to factor in this caveat when you're implementing your stories.

</Callout>

<!-- End if react -->
</If>

## Creating a Template Component

Another option that is more “data”-based is to create a special “story-generating” template component:
Expand Down

0 comments on commit 6af31bf

Please sign in to comment.