When creating components for reuse, you can document them in our Storybook for designers and developers alike. The purpose of the stories should be to show the different visual states of the component, and document the component's props (args in Storybook) and their possible values for developer's.
In ui-core package, alongside the component files you will find the majority of *.stories.tsx files. There are also in other ui packages as well as the dispatch app.
If you are unfamiliar with writing stories, please review this doc in Storybook for an introduction.
Here we will review a few guidelines to keep stories standardized, no matter who writes them.
Coming soon: Link to Cursor prompt to help write stories
Defining argTypes in Storybook will specify the controls used for each arg (prop) that a story will take. Using the Meta config to define argTypes allows us to set all the controls a story will have available. In the individual story you can decide to list them all, include or exclude args to make the story simpler with a smaller subset of interactive controls.
Here's an example:
The above will render out controls for id, defaultValue, disabled and indicatorPosition args. The id control will be shown as required with an asterisk. The disabled arg will have a switch control for booleans.
indicatorPosition since its a prop that takes IndicatorPositionEnum values, uses enumToArgType util
that will return an argType object that renders a select control with appropriate values and labels that correspond to the enum.
All args will be sorted in alphabetical order.
From here, subsequent stories will inherit the same controls list.
Start with a general or "Default" story of a basic example.
This default story should list all the props as args that the component accepts, so the engineer can get an idea of the component's API.
If you define all the argTypes in the Meta object, then you should get this list in the Default story.
Try to have a story for each variant or state that the component can be in. In these stories, args edits should impact the story - e.g. when the viewer uses a control to set or change a value, the story should change. In order to do this, the component rendered in the story should accept the args as props (args passed to the render function).
Consider limiting args shown in a story with include or exclude, in order to only expose a few that make sense to edit (like the "Disabled" story example below).
In stories that represent a particular state, include only the args whose controls will change will have an impact on that state.
To achieve this, we can include or exclude the controls and make stories with particular states simpler.
For example, if we want a "Disabled" story to show the disabled state, we can only include a couple of args that are necessary to allow the viewer to manipulate those args.
include and exclude are described in the Storybook docs on argTypes. Gotcha: If you use include or exclude, be sure to pass args (or _args if not using them) to the render function or it will be ignored.
Sometimes it makes sense to group a bunch of variations in one story and show them side by side, like when they are colors, icons or positions for example. If you have a story that shows all, the controls will probably not be used to change props for all the rendered components.
You can still list all the args to show the API, but use the util disableArgControls to disable their controls, since changing values shouldn't have any effect.
We have disabled snapshots globally for all stories, so you need to be intentional about which stories you want to snapshot.
Try and snapshot at least one story representation per component, espercially stories that illustarte multiple variants (colors, positions, disabled).
Wrap your story in the WithSnapshot helper in order to Chromatic snapshots for that story. Local publishes use pnpm chromatic from the repo root.
We use Storybook with the vitest addon in order to trun stories into tests.
At the basic level even if it doesn't have explicit tests, each component will test if it renders and error if it throws an error while rendering.
Consider testing interactive components by adding a play method to the story.
You can create a particular story just for tests if it makes sense.
You can use the "Interaction Recorder" tool in Storybook to help generate a test.
When testing, folow the same guidelines as our e2e tests and test things as they are seen by the user (not classnames, test ids) whenever possible.