[RFC]: Typesafe CSF factories #30112
kasperpeulen
started this conversation in
RFC
Replies: 1 comment
-
Love this, have definitely been feeling the pain points listed here!
// AllOfMy.stories.ts
import preview from '#.storybook/preview';
import { Button } from './Button';
import { Tooltip } from './Tooltip';
const meta = preview.meta({ component: Button });
export const Primary = meta.story({
args: {
primary: true,
label: 'Button',
},
});
const tooltipMeta = preview.meta({ component: Tooltip });
export const Tooltip = tooltipMeta.story({
args: {
primary: true,
label: 'Tooltip',
},
}); This might be out of scope but one other thing regarding typing that could be improved is that parameters are not typed. Maybe there is a way to allow for type augmentation of parameters here in a way that we could get autocomplete when writing e.g. const tooltipMeta = preview.meta({ component: Tooltip });
export const Tooltip = tooltipMeta.story({
args: {
primary: true,
label: "Tooltip",
},
parameters: {
docs: {
description: {
story: "Hover to see the tooltip.",
},
story: {
height: "500px",
inline: false,
},
},
},
}); Maybe this is already possible? |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
RFC: Typesafe CSF factories
Storybook's current syntax lacks the modern, developer-friendly features that competing tools offer, such as autocomplete and discoverability. Developers need to remember Storybook-specific jargon, which creates a high cognitive load. Other tools in the ecosystem have standardized the factory pattern (e.g.
defineConfig
), which offers intuitive autocomplete and suggestions that make the experience seamless. Without these features, users struggle to configure addons correctly and may overlook valuable features Storybook offers.Introducing CSF factories
Writing a type-safe CSF3 story typically involves a significant boilerplate. Here's an example of a standard CSF3 story for a
Button
component:To streamline this process, we can introduce factories that require no extra type annotations for type safety. Here's how the
Button
story would look using factories:This approach reduces the need for explicit type declarations and manual repetitive code, minimizing the chances of errors. It makes the story definitions more concise and easier to understand.
The preview file
The preview file is central to configuring Storybook's behavior and addons. Here's a
.storybook/preview.ts
file using the proposeddefineConfig
factory:To leverage type information from addons within your stories, explicitly import the preview config:
Note: While you can use relative imports for the preview file, we recommend adopting this standard-based absolute import convention, popularized by Kent C. Dodds. Learn more about this convention.
Factory for CSF1-style stories
It is still popular to write stories as a component when using React:
We will always keep supporting this pattern, but it will also be possible to do this typesafely with factories:
Resolving the documentation burden
Currently, there are 3 syntaxes that users can write CSF in (TS 4.9+, TS4.8- and pure JS):
Supporting three different syntaxes (TypeScript 4.9+, TypeScript 4.8-, pure Javascript) increases documentation complexity and user confusion.
With factories, we can have the same syntax for those 3 different sets of users. And it achieves the same or better type safety, but with a single clean syntax that provides great autocompletion:
Non-component args (Future proposal)
At some point we want to support non-component args prefixed with a
$
. Normally, all args of the story are automatically applied as props of the component. We would like to introduce “$-prefixed-args” (aka non-component args) as a way to get all the power of controls and args for other purposes (aside from component props).In this way, you can use mock data in a fully declarative way and control this data in the control panel:
Non-component args are not a part of this proposal. Another proposal for that will come and we also consider making all parameters controllable in the controls addon, as that would fulfil the same purpose of non-component args.
Multiple preview configs
Stories for page components might need completely different defaults than story for design system components. Being able to write multiple story configs solves this:
Infer type information from argTypes/globalTypes
In some cases, the props of the component are less interesting than the child that you can put inside of it. For this, you might want to use custom args that are unrelated to the props.
Getting this correct with typescript in CSF3 is quite a challenge at the moment. But with factories we can support inferred patterns like below:
Another case, where we can infer the type from runtime information is
globals
:Make a default export optional
Previous we needed the meta to be exported. For CSF factories this is not necessary anymore:
The meta runtime information is automatically merged with every story, so we don’t need it for that reason.
We also extract some data at compile time for the sidebar (like the name, title of the story).
The runtime information with factories will be automatically merged. And the compile time information, can also be extracted by looking at the
meta
call in the AST tree.Stories are portable by default
This also means that stories are completely portable by default. Every story will be fully prepared with all the preview and meta annotations, and you don’t need to call setProjectAnnotations in your test setup (e.g. for the vitest integration).
Extending a story
You will be able to create a new story from an existing story:
Here, the same inheritance is used as when you go from
meta
to astory
. Args and parameters are deep-merged, decorators are added, and render/play function is overridden.Beta Was this translation helpful? Give feedback.
All reactions