title |
---|
Controls |
Storybook Controls gives you a graphical UI to interact with a component's arguments dynamically without needing to code. It creates an addon panel next to your component examples ("stories"), so you can edit them live.
Controls do not require any modification to your components. Stories for controls are:
- Convenient. Auto-generate controls based on React/Vue/Angular/etc. components.
- Portable. Reuse your interactive stories in documentation, tests, and even in designs.
- Rich. Customize the controls and interactive data to suit your exact needs.
To use the Controls addon, you need to write your stories using args. Storybook will automatically generate UI controls based on your args and what it can infer about your component. Still, you can configure the controls further using argTypes, see below.
If you have stories in the older pre-Storybook 6 style, check the args & controls migration guide to learn how to convert your existing stories for args.
By default, Storybook will try to infer the required argTypes and associated controls for your stories based on the component's definition and initial value of the args using Compodoc, a documentation generator for Angular applications that can extract the metadata of your components, including first-class support for Angular's inputs
, outputs
, properties
, methods
, and view/content child/children
. If you opt-in to use it, you must take additional steps to set it up properly.
Run the following command to install the tooling.
<CodeSnippets paths={[ 'angular/compodoc-install.yarn.js.mdx', 'angular/compodoc-install.npm.js.mdx', 'angular/compodoc-install.pnpm.js.mdx', ]} />
Update your angular.json
file to include the following configuration to include it in the Storybook's inbuilt builder configuration.
<CodeSnippets paths={[ 'angular/angular-project-compodoc-config.json.mdx', ]} />
Finally, update your .storybook/preview.ts
file to include the following configuration to import the metadata generated by Compodoc and use it to generate the controls and argTypes for your stories.
<CodeSnippets paths={[ 'angular/storybook-preview-compodoc-config.ts.mdx', ]} />
When you set the component
annotation of the default export of your story file, it will be used to infer the controls and auto-generate the matching argTypes
for your component.
<CodeSnippets paths={[ 'angular/button-story-default-export-with-component.ts.mdx', ]} />
By default, Storybook will try to infer the required argTypes and associated controls for your stories based on the metadata provided by the @storybook/ember-cli-storybook
adapter. You'll need to take some additional steps to set it up properly.
Update your ember-cli-build.js
configuration file to include the adapter.
<CodeSnippets paths={[ 'ember/storybook-ember-cli-build.js.mdx', ]} />
Restart your application to generate the metadata file (i.e., storybook-docgen/index.json
) and update your .storybook/preview.js
file to include it, which will be used to create the controls and argTypes for your stories.
<CodeSnippets paths={[ 'ember/storybook-preview-custom-metadata.js.mdx', ]} />
Enabling this feature will generate a storybook-docgen/index.json
automatically with each build. For more information on how the metadata is generated, refer to documentation for the Ember framework.
When you set the component
annotation of the default export of your story file, it will be used to infer the controls and auto-generate the matching argTypes
for your component.
<CodeSnippets paths={[ 'ember/button-story-default-export-with-component.js.mdx', ]} />
By default, Storybook will choose a control for each arg based on its initial value. This will work well with specific arg types (e.g., boolean
or string
). To enable them, add the component
annotation to the default export of your story file, and it will be used to infer the controls and auto-generate the matching argTypes
for your component using react-docgen
, a documentation generator for React components that also includes first-class support for TypeScript.
<CodeSnippets paths={[ 'react/button-story-default-export-with-component.js.mdx', 'react/button-story-default-export-with-component.ts.mdx', ]} />
By default, Storybook will choose a control for each arg based on its initial value. This will work well with specific arg types (e.g., boolean
or string
). To enable them, add the component
annotation to the default export of your story file, and it will be used to infer the controls and auto-generate the matching argTypes
for your component using vue-docgen-api
, including first-class support for Vue's props
, events
, and slots
.
<CodeSnippets paths={[ 'vue/button-story-default-export-with-component.js.mdx', 'vue/button-story-default-export-with-component.ts.mdx', ]} />
By default, Storybook will try to infer the required argTypes and associated controls for your stories based on the component's definition and the initial value of the args. You'll need to take some additional steps to set it up properly. You can opt to generate a custom-elements.json
file with @custom-elements-manifest/analyzer
if you're using the pre-v1.0.0
version of the elements file or @custom-elements-manifest/analyzer
for newer versions and configure it in your Storybook UI configuration file (i.e., .storybook/preview.js|ts
) to enable it.
<CodeSnippets paths={[ 'web-components/storybook-preview-custom-elements-config.js.mdx', 'web-components/storybook-preview-custom-elements-config.ts.mdx', ]} />
When you set the component
annotation of the default export of your story file, it will be used to infer the controls and auto-generate the matching argTypes
for your component.
<CodeSnippets paths={[ 'web-components/button-story-default-export-with-component.js.mdx', 'web-components/button-story-default-export-with-component.ts.mdx', ]} />
<IfRenderer renderer={[ 'html', 'svelte', 'preact', 'qwik', 'solid' ]}>
By default, Storybook will choose a control for each arg based on its initial value. This will work well with specific arg types (e.g., boolean
or string
). To enable them, add the component
annotation to the default export of your story file, and it will be used to infer the controls and auto-generate the matching argTypes
for your component provided by the framework you've chosen to use.
<CodeSnippets paths={[ 'preact/button-story-default-export-with-component.js.mdx', 'svelte/button-story-default-export-with-component.js.mdx', 'svelte/button-story-default-export-with-component.ts.mdx', 'solid/button-story-default-export-with-component.js.mdx', 'solid/button-story-default-export-with-component.ts.mdx', ]} />
If you're using a framework that doesn't support this feature, you'll need to define the argTypes
for your component manually.
For instance, suppose you have a variant
arg on your story that should be primary
or secondary
:
<CodeSnippets paths={[ 'angular/button-story-controls-primary-variant.ts.mdx', 'web-components/button-story-controls-primary-variant.js.mdx', 'web-components/button-story-controls-primary-variant.ts.mdx', 'common/button-story-controls-primary-variant.js.mdx', 'common/button-story-controls-primary-variant.ts.mdx', ]} usesCsf3 csf2Path="essentials/controls#snippet-button-story-controls-primary-variant" />
By default, Storybook will render a free text input for the variant
arg:
It works as long as you type a valid string into the auto-generated text control. Still, it's not the best UI for our scenario, given that the component only accepts primary
or secondary
as variants. Let’s replace it with Storybook’s radio component.
We can specify which controls get used by declaring a custom argType for the variant
property. ArgTypes encode basic metadata for args, such as name, description, and defaultValue for an arg. These get automatically filled in by Storybook Docs.
ArgTypes
can also contain arbitrary annotations, which the user can override. Since variant
is a property of the component, let's put that annotation on the default export.
<CodeSnippets paths={[ 'angular/button-story-controls-radio-group.ts.mdx', 'web-components/button-story-controls-radio-group.js.mdx', 'web-components/button-story-controls-radio-group.ts.mdx', 'common/button-story-controls-radio-group.js.mdx', 'common/button-story-controls-radio-group.ts.mdx', ]} />
ArgTypes are a powerful feature that can be used to customize the controls for your stories. For more information, see the documentation about customizing controls with argTypes
annotation.
This replaces the input with a radio group for a more intuitive experience.
Controls can automatically be inferred from arg's name with regex, but currently only for the color picker and date picker controls. If you've used the Storybook CLI to setup your project, it should have automatically created the following defaults in .storybook/preview.js
:
Control | Default regex | Description |
---|---|---|
color | /(background|color)$/i |
Will display a color picker UI for the args that match it |
date | /Date$/ |
Will display a date picker UI for the args that match it |
If you haven't used the CLI to set the configuration, or if you want to define your patterns, use the matchers
property in the controls
parameter:
<CodeSnippets paths={[ 'common/storybook-addon-controls-custom-matchers.js.mdx', 'common/storybook-addon-controls-custom-matchers.ts.mdx', ]} />
<IfRenderer renderer={['angular', 'ember', 'html', 'preact', 'qwik', 'react', 'solid', 'vue', 'web-components' ]}>
Until now, we only used auto-generated controls based on the component for which we're writing stories. If we are writing complex stories, we may want to add controls for args that aren’t part of the component. For example, here's how you could use a footer
arg to populate a child component:
<CodeSnippets paths={[ 'react/page-story-slots.js.mdx', 'react/page-story-slots.ts.mdx', 'vue/page-story-slots.3.js.mdx', 'vue/page-story-slots.3.ts.mdx', 'angular/page-story-slots.ts.mdx', 'web-components/page-story-slots.js.mdx', 'web-components/page-story-slots.ts.mdx', 'solid/page-story-slots.js.mdx', 'solid/page-story-slots.ts.mdx', ]} usesCsf3 csf2Path="writing-stories/args#snippet-page-story-slots" />
By default, Storybook will add controls for all args that:
-
It infers from the component definition if your framework supports it.
-
Appear in the list of args for your story.
Using argTypes
, you can change the display and behavior of each control.
When dealing with non-primitive values, you'll notice that you'll run into some limitations. The most obvious issue is that not every value can be represented as part of the args
param in the URL, losing the ability to share and deep link to such a state. Beyond that, complex values such as JSX cannot be synchronized between the manager (e.g., Controls addon) and the preview (your story).
One way to deal with this is to use primitive values (e.g., strings) as arg values and add a custom render
function to convert them to their complex counterpart before rendering. It isn't the nicest way to do it (see below), but certainly the most flexible.
<CodeSnippets paths={[ 'react/component-story-custom-args-complex.js.mdx', 'react/component-story-custom-args-complex.ts.mdx', 'vue/component-story-custom-args-complex.js.mdx', 'vue/component-story-custom-args-complex.ts.mdx', 'angular/component-story-custom-args-complex.ts.mdx', 'svelte/component-story-custom-args-complex.js.mdx', 'svelte/component-story-custom-args-complex.ts.mdx', 'web-components/component-story-custom-args-complex.js.mdx', 'web-components/component-story-custom-args-complex.ts.mdx', 'solid/component-story-custom-args-complex.js.mdx', 'solid/component-story-custom-args-complex.ts.mdx', ]} usesCsf3 csf2Path="essentials/controls#snippet-component-story-custom-args-complex" />
Unless you need the flexibility of a function, an easier way to map primitives to complex values before rendering is to define a mapping
; additionally, you can specify control.labels
to configure custom labels for your checkbox, radio, or select input.
<CodeSnippets paths={[ 'angular/component-story-custom-args-mapping.ts.mdx', 'web-components/component-story-custom-args-mapping.js.mdx', 'web-components/component-story-custom-args-mapping.ts.mdx', 'common/component-story-custom-args-mapping.js.mdx', 'common/component-story-custom-args-mapping.ts.mdx', ]} />
Note that both mapping
and control.labels
don't have to be exhaustive. If the currently selected option is not listed, it's used verbatim.
The Controls addon can be configured in two ways:
- Individual controls can be configured via control annotations.
- The addon's appearance can be configured via parameters.
As shown above, you can configure individual controls with the “control" annotation in the argTypes field of either a component or story. Below is a condensed example and table featuring all available controls.
Data Type | Control | Description |
---|---|---|
boolean | boolean |
Provides a toggle for switching between possible states.argTypes: { active: { control: 'boolean' }} |
number | number |
Provides a numeric input to include the range of all possible values.argTypes: { even: { control: { type: 'number', min:1, max:30, step: 2 } }} |
range |
Provides a range slider component to include all possible values.argTypes: { odd: { control: { type: 'range', min: 1, max: 30, step: 3 } }} |
|
object | object |
Provides a JSON-based editor component to handle the object's values. Also allows edition in raw mode. argTypes: { user: { control: 'object' }} |
array | object |
Provides a JSON-based editor component to handle the array's values. Also allows edition in raw mode. argTypes: { odd: { control: 'object' }} |
file |
Provides a file input component that returns an array of URLs. Can be further customized to accept specific file types. argTypes: { avatar: { control: { type: 'file', accept: '.png' } }} |
|
enum | radio |
Provides a set of radio buttons based on the available options.argTypes: { contact: { control: 'radio', options: ['email', 'phone', 'mail'] }} |
inline-radio |
Provides a set of inlined radio buttons based on the available options.argTypes: { contact: { control: 'inline-radio', options: ['email', 'phone', 'mail'] }} |
|
check |
Provides a set of checkbox components for selecting multiple options.argTypes: { contact: { control: 'check', options: ['email', 'phone', 'mail'] }} |
|
inline-check |
Provides a set of inlined checkbox components for selecting multiple options.argTypes: { contact: { control: 'inline-check', options: ['email', 'phone', 'mail'] }} |
|
select |
Provides a drop-down list component to handle single value selection. argTypes: { age: { control: 'select', options: [20, 30, 40, 50] }} |
|
multi-select |
Provides a drop-down list that allows multiple selected values. argTypes: { countries: { control: 'multi-select', options: ['USA', 'Canada', 'Mexico'] }} |
|
string | text |
Provides a freeform text input. argTypes: { label: { control: 'text' }} |
color |
Provides a color picker component to handle color values. Can be additionally configured to include a set of color presets. argTypes: { color: { control: { type: 'color', presetColors: ['red', 'green']} }} |
|
date |
Provides a datepicker component to handle date selection. argTypes: { startDate: { control: 'date' }} |
The date
control will convert the date into a UNIX timestamp when the value changes. It's a known limitation that will be fixed in a future release. If you need to represent the actual date, you'll need to update the story's implementation and convert the value into a date object.
<CodeSnippets paths={[ 'angular/gizmo-story-controls-customization.ts.mdx', 'web-components/gizmo-story-controls-customization.js.mdx', 'web-components/gizmo-story-controls-customization.ts.mdx', 'common/gizmo-story-controls-customization.js.mdx', 'common/gizmo-story-controls-customization.ts.mdx', ]} />
Numeric data types will default to a number
control unless additional configuration is provided.
Controls supports the following configuration parameters, either globally or on a per-story basis:
Since Controls is built on the same engine as Storybook Docs, it can also show property documentation alongside your controls using the expanded parameter (defaults to false). This means you embed a complete Controls
doc block in the controls panel. The description and default value rendering can be customized like the doc block.
To enable expanded mode globally, add the following to .storybook/preview.js
:
<CodeSnippets paths={[ 'common/storybook-preview-expanded-controls.js.mdx', 'common/storybook-preview-expanded-controls.ts.mdx', ]} />
Here's what the resulting UI looks like:
For color
controls, you can specify an array of presetColors
, either on the control
in argTypes
, or as a parameter under the controls
namespace:
<CodeSnippets paths={[ 'common/storybook-preview-parameters-color-swatches.js.mdx', 'common/storybook-preview-parameters-color-swatches.ts.mdx', ]} />
Color presets can be defined as an object with color
and title
or a simple CSS color string. These will then be available as swatches in the color picker. When you hover over the color swatch, you'll be able to see its title. It will default to the nearest CSS color name if none is specified.
In specific cases, you may be required to display only a limited number of controls in the controls panel or all except a particular set.
To make this possible, you can use optional include
and exclude
configuration fields in the controls
parameter, which you can define as an array of strings or a regular expression.
Consider the following story snippets:
<CodeSnippets paths={[ 'angular/component-story-disable-controls-regex.ts.mdx', 'web-components/component-story-disable-controls-regex.js.mdx', 'web-components/component-story-disable-controls-regex.ts.mdx', 'common/component-story-disable-controls-regex.js.mdx', 'common/component-story-disable-controls-regex.ts.mdx', ]} usesCsf3 csf2Path="essentials/controls#snippet-component-story-disable-controls-regex" />
By default, controls are unsorted and use whatever order the args data is processed in (none
). Additionally, you can sort them alphabetically by the arg's name (alpha
) or with the required args first (requiredFirst
).
Consider the following snippet to force required args first:
<CodeSnippets paths={[ 'angular/component-story-sort-controls.ts.mdx', 'web-components/component-story-sort-controls.js.mdx', 'web-components/component-story-sort-controls.ts.mdx', 'common/component-story-sort-controls.js.mdx', 'common/component-story-sort-controls.ts.mdx', ]} />
Aside from the features already documented here, Controls can also be disabled for individual properties.
Suppose you want to turn off Controls for a property called foo
in a component's story. The following example illustrates how:
<CodeSnippets paths={[ 'angular/component-story-disable-controls.ts.mdx', 'web-components/component-story-disable-controls.js.mdx', 'web-components/component-story-disable-controls.ts.mdx', 'common/component-story-disable-controls.js.mdx', 'common/component-story-disable-controls.ts.mdx', ]} />
Resulting in the following change in Storybook UI:
The previous example also removed the prop documentation from the table. In some cases, this is fine. However, sometimes you might want to render the prop documentation without a control. The following example illustrates how:
<CodeSnippets paths={[ 'angular/component-story-disable-controls-alt.ts.mdx', 'web-components/component-story-disable-controls-alt.js.mdx', 'web-components/component-story-disable-controls-alt.ts.mdx', 'common/component-story-disable-controls-alt.js.mdx', 'common/component-story-disable-controls-alt.ts.mdx', ]} />
As with other Storybook properties, such as decorators, you can apply the same pattern at a story level for more granular cases.
In some cases, it's useful to be able to conditionally exclude a control based on the value of another control. Controls supports basic versions of these use cases with the if
, which can take a simple query object to determine whether to include the control.
Consider a collection of "advanced" settings only visible when the user toggles an "advanced" toggle.
<CodeSnippets paths={[ 'angular/component-story-conditional-controls-toggle.ts.mdx', 'web-components/component-story-conditional-controls-toggle.js.mdx', 'web-components/component-story-conditional-controls-toggle.ts.mdx', 'common/component-story-conditional-controls-toggle.js.mdx', 'common/component-story-conditional-controls-toggle.ts.mdx', ]} />
Or consider a constraint where if the user sets one control value, it doesn't make sense for the user to be able to set another value.
<CodeSnippets paths={[ 'angular/component-story-conditional-controls-mutual-exclusion.ts.mdx', 'web-components/component-story-conditional-controls-mutual-exclusion.js.mdx', 'web-components/component-story-conditional-controls-mutual-exclusion.ts.mdx', 'common/component-story-conditional-controls-mutual-exclusion.js.mdx', 'common/component-story-conditional-controls-mutual-exclusion.ts.mdx', ]} />
The query object must contain either an arg
or global
target:
field | type | meaning |
---|---|---|
arg | string | The ID of the arg to test. |
global | string | The ID of the global to test. |
It may also contain at most one of the following operators:
operator | type | meaning |
---|---|---|
truthy | boolean | Is the target value truthy? |
exists | boolean | Is the target value defined? |
eq | any | Is the target value equal to the provided value? |
neq | any | Is the target value NOT equal to the provided value? |
If no operator is provided, that is equivalent to { truthy: true }
.
<IfRenderer renderer={[ 'angular', 'ember', 'web-components' ]}>
If you're working with Angular, Ember, or Web Components, automatic argTypes and controls inference will not work out of the box and requires you to provide additional configuration to allow Storybook to retrieve the necessary metadata and generate the needed argTypes and controls for your stories. However, if you need additional customization, you can always define them manually.
This addon contributes the following parameters to Storybook, under the controls
namespace:
Type: boolean
Disable this addon's behavior. If you wish to disable this addon for the entire Storybook, you should do so when registering addon-essentials
. See the essential addon's docs for more information.
This parameter is most useful to allow overriding at more specific levels. For example, if this parameter is set to true
at the project level, it could then be re-enabled by setting it to false
at the meta (component) or story level.
Type: string[] | RegExp
Specifies which properties to exclude from the Controls addon panel. Any properties whose names match the regex or are part of the array will be left out. See usage example, above.
Type: boolean
Show the full documentation for each property in the Controls addon panel, including the description and default value. See usage example, above.
Type: string[] | RegExp
Specifies which properties to include in the Controls addon panel. Any properties whose names don't match the regex or are not part of the array will be left out. See usage example, above.
Type: (string | { color: string; title?: string })[]
Specify preset color swatches for the color picker control. The color value may be any valid CSS color. See usage example, above.
Type: 'none' | 'alpha' | 'requiredFirst'
Default: 'none'
Specifies how the controls are sorted.
- none: Unsorted, displayed in the same order the arg types are processed in
- alpha: Sorted alphabetically, by the arg type's name
- requiredFirst: Same as
alpha
, with any required arg types displayed first