Write notes for your Storybook stories.
npx @tessl/cli install tessl/npm-storybook--addon-notes@5.3.0Storybook Addon Notes allows you to write notes (text or HTML) for your stories in Storybook. It provides both tab-based and panel-based display modes for documentation, supports Markdown rendering with embedded Giphy support, and enables multiple notes sections for different audiences (design, development).
npm install -D @storybook/addon-notesThe addon integrates with Storybook's parameter system rather than providing direct imports for normal usage. For addon registration:
// In .storybook/main.js
module.exports = {
addons: ['@storybook/addon-notes/register'] // or 'register-panel'
};Deprecated decorator functions (avoid in new code):
import { withNotes, withMarkdownNotes } from '@storybook/addon-notes';Register the addon in your .storybook/main.js:
module.exports = {
addons: ['@storybook/addon-notes/register']
}Add notes to stories using the notes parameter:
export default {
title: 'Component',
parameters: {
notes: 'Simple text notes for this story',
},
};
export const BasicStory = () => <Component />;Alternatively, register as a panel instead of a tab:
module.exports = {
addons: ['@storybook/addon-notes/register-panel']
}Add simple text notes to stories using a string parameter.
// Story configuration with text notes
export default {
parameters: {
notes: 'Simple text notes for this story',
},
};Add markdown-formatted notes with rich content support.
import markdownNotes from './notes.md';
export default {
parameters: {
notes: { markdown: markdownNotes },
},
};Add text notes using object format for consistency.
export default {
parameters: {
notes: { text: 'Text content for the notes panel' },
},
};Create multiple named sections for different audiences or topics.
import introNotes from './intro.md';
import designNotes from './design.md';
export default {
parameters: {
notes: {
'Introduction': introNotes,
'Design Notes': designNotes
},
},
};Embed Giphy GIFs in markdown notes using the custom Giphy component. The component fetches the first result from Giphy's search API.
interface GiphyProps {
query: string; // Search term for Giphy API
}
class Giphy extends Component<GiphyProps, GiphyState> {
componentDidMount(): void;
render(): React.ReactElement | null;
}Usage in Markdown:
# Story Notes
This component handles user interactions.
<Giphy query="celebration" />
More documentation content here...Disable notes display for specific stories.
export default {
parameters: {
notes: { disable: true },
},
};Note: These decorators are deprecated and should not be used in new code.
/**
* @deprecated Use parameter-based notes instead
*/
function withNotes(options: string | NotesOptions): any;
/**
* @deprecated Use parameter-based notes instead
*/
function withMarkdownNotes(text: string, options: any): void;
// Internal utility functions
function formatter(code: string): string;// Parameter types
type Parameters =
| string
| TextParameter
| MarkdownParameter
| DisabledParameter
| TabsParameter;
interface TextParameter {
text: string;
}
interface MarkdownParameter {
markdown: string;
}
interface DisabledParameter {
disable: boolean;
}
type TabsParameter = Record<string, string>;
// Component props
interface PanelProps {
active: boolean;
api: API;
}
interface GiphyProps {
query: string;
}
interface GiphyState {
src: string | null;
}
interface SyntaxHighlighterProps {
className?: string;
children: ReactElement;
[key: string]: any;
}
interface NotesLinkProps {
href: string;
children: ReactElement;
}const ADDON_ID = 'storybookjs/notes';
const PANEL_ID = 'storybookjs/notes/panel';
const PARAM_KEY = 'notes';
// Registration entry points
const REGISTER_TAB = '@storybook/addon-notes/register';
const REGISTER_PANEL = '@storybook/addon-notes/register-panel';The addon automatically handles:
<Giphy query="search-term" />Notes can be configured at different levels:
// Component-level notes (applies to all stories)
export default {
title: 'Components/Button',
parameters: {
notes: 'General button component documentation',
},
};
// Story-level notes (overrides component-level)
export const PrimaryButton = () => <Button primary />;
PrimaryButton.story = {
parameters: {
notes: 'Specific notes for the primary button variant',
},
};Works seamlessly with Component Story Format (CSF):
import Component from './Component';
import componentNotes from './Component.notes.md';
export default {
title: 'Component',
component: Component,
parameters: {
notes: { markdown: componentNotes },
},
};
export const Default = {};
export const WithCustomNotes = {
parameters: {
notes: 'Story-specific notes override component notes',
},
};The addon includes an internal formatter that normalizes whitespace in template literals:
/**
* Formats code strings by removing common indentation from template literals
* @param code - Raw code string to format
* @returns Formatted code string with normalized whitespace
*/
function formatter(code: string): string;The addon handles various error conditions gracefully:
Example error scenarios:
// Invalid parameter format - throws error
export default {
parameters: {
notes: { /* missing text or markdown property */ }
}
};
// Network error handling - graceful fallback
// If Giphy API fails, the component simply doesn't renderThe addon supports two display modes:
@storybook/addon-notes/register): Notes appear in a dedicated tab in the addons panel@storybook/addon-notes/register-panel): Notes appear directly in the main addons panel areaChoose the mode that best fits your Storybook configuration and team preferences.
The addon supports custom markdown component overrides and theming:
// Custom markdown components can be registered
import { addons, types } from '@storybook/addons';
// Register custom elements that will be available in markdown
addons.getChannel().emit('addElement', {
type: types.NOTES_ELEMENT,
id: 'my-custom-element',
render: ({ children }) => <div className="custom">{children}</div>
});Styling Considerations:
The addon uses Storybook's theming system and can be customized via the theme:
// In .storybook/manager.js
import { themes } from '@storybook/theming';
import { addons } from '@storybook/addons';
addons.setConfig({
theme: {
...themes.normal,
addonNotesTheme: {
fontFamily: 'Monaco, monospace',
fontSize: '14px'
}
}
});