React Storybook: Isolate React Component Development with Hot Reloading.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Extensible plugin system for adding custom functionality to the Storybook interface and development workflow. Addons provide additional methods to the Story API and can integrate with the Storybook UI.
Registers addon methods to the Story API, making them available as chainable methods on story collections.
/**
* Registers addon methods to the Story API
* @param addon - Object containing methods to add to Story instances
*/
function setAddon(addon: Object): void;Usage Examples:
import { setAddon, storiesOf } from '@kadira/storybook';
// Simple addon that adds a method to stories
setAddon({
addWithInfo(storyName, info, storyFn) {
return this.add(storyName, () => (
<div>
<div style={{ padding: '10px', backgroundColor: '#f0f0f0' }}>
<strong>Info:</strong> {info}
</div>
{storyFn()}
</div>
));
}
});
// Now use the addon method on any story collection
storiesOf('Button', module)
.addWithInfo('default', 'A basic button component', () =>
<Button>Click me</Button>
)
.addWithInfo('primary', 'Primary variant of the button', () =>
<Button primary>Primary</Button>
);
// Multiple addon methods
setAddon({
addWithProps(name, props, component) {
return this.add(name, () => React.createElement(component, props));
},
addVariants(baseName, variants, component) {
variants.forEach(variant => {
this.add(`${baseName} - ${variant.name}`, () =>
React.createElement(component, variant.props)
);
});
return this;
}
});
// Usage of multiple addon methods
storiesOf('Input', module)
.addWithProps('disabled', { disabled: true, value: 'Disabled' }, Input)
.addVariants('sizes', [
{ name: 'small', props: { size: 'small' } },
{ name: 'large', props: { size: 'large' } }
], Input);Storybook comes with several built-in addons that provide common functionality.
The core addon system that manages addon registration and communication.
import addons from '@kadira/storybook-addons';
// Access the addon channel for custom communication
const channel = addons.getChannel();
channel.emit('my-event', { data: 'example' });Built-in addon for logging component interactions and events.
import { action } from '@kadira/storybook-addon-actions';
// Available as re-export from main package
import { action } from '@kadira/storybook';
storiesOf('Interactive Button', module)
.add('with click handler', () => (
<Button onClick={action('button-clicked')}>
Click me to see action log
</Button>
))
.add('with multiple events', () => (
<Input
onChange={action('input-changed')}
onFocus={action('input-focused')}
onBlur={action('input-blurred')}
/>
));Built-in addon for creating navigation links between stories.
import { linkTo } from '@kadira/storybook-addon-links';
// Available as re-export from main package
import { linkTo } from '@kadira/storybook';
storiesOf('Navigation', module)
.add('go to button', () => (
<div>
<p>Click below to navigate to Button stories</p>
<button onClick={linkTo('Button', 'default')}>
Go to Button Default
</button>
</div>
))
.add('conditional navigation', () => (
<Button onClick={linkTo('Form', 'input')}>
Go to Form Input Story
</Button>
));Creating custom addons for specific project needs.
Basic Custom Addon:
// Define the addon object
const myCustomAddon = {
addWithWrapper(storyName, wrapperStyle, storyFn) {
return this.add(storyName, () => (
<div style={wrapperStyle}>
{storyFn()}
</div>
));
},
addWithBackground(storyName, backgroundColor, storyFn) {
return this.addWithWrapper(storyName, { backgroundColor }, storyFn);
}
};
// Register the addon
setAddon(myCustomAddon);
// Use the addon methods
storiesOf('Styled Components', module)
.addWithBackground('on blue', '#e3f2fd', () => <Card />)
.addWithBackground('on green', '#e8f5e8', () => <Card />);Advanced Custom Addon with State:
const stateAddon = {
addWithState(storyName, initialState, storyFn) {
return this.add(storyName, () => {
const [state, setState] = React.useState(initialState);
return storyFn(state, setState);
});
}
};
setAddon(stateAddon);
storiesOf('Stateful Components', module)
.addWithState('counter', { count: 0 }, (state, setState) => (
<div>
<p>Count: {state.count}</p>
<button onClick={() => setState({ count: state.count + 1 })}>
Increment
</button>
</div>
));Standard addon development typically follows this structure:
my-custom-addon/
├── package.json
├── src/
│ ├── index.js # Main addon logic
│ ├── register.js # UI panel registration
│ └── components/ # Addon UI components
└── README.mdExample Addon Entry Point:
// src/index.js
export const myAddon = {
addWithCustomLayout(storyName, layoutProps, storyFn) {
return this.add(storyName, () => (
<CustomLayout {...layoutProps}>
{storyFn()}
</CustomLayout>
));
}
};
// Auto-register if imported
import { setAddon } from '@kadira/storybook';
setAddon(myAddon);interface AddonObject {
/** Custom methods to add to Story API */
[methodName: string]: Function;
}
interface StoryAPI {
/** Add a story to this collection */
add(storyName: string, storyFunction: Function): StoryAPI;
/** Add a decorator to this collection */
addDecorator(decorator: Function): StoryAPI;
/** The story collection name */
kind: string;
/** Any addon methods registered via setAddon */
[addonMethod: string]: Function;
}