Documenting Storybook with TS and JSDocs
/**
* JSDoc
*/
JSDoc
/**
/** Adds two numbers together */
function add(a, b) {
return a + b;
}
JSDoc
/**
* Adds two numbers together
* @deprecated since version 2.0
* @param {number} a any number
* @param {number} b any number
*/
function add(a, b) {
return a + b;
}
JSDoc
Benefits
- Documentation lives with the code.
- Tools can create documentation from those code comments
Limitations
- Advanced types are not supported
- e.g. generics
- Types are only documented and not enforced
// No errors, including runtime
add("1", 2) // returns "12"
TypeScript
function add(a: number, b: number): number {
return a + b;
}
TypeScript
Benefits
- Advanced types are supported
- New JavaScript features are supported through transpilation.
- Types are enforced and will error at compilation time.
Limitations
- TypeScript not intended to document code.
interface Props {
size?: number | string;
}
What is the size prop really looking for?
TS + JSDoc = 💪
/**
* Adds two numbers together
* @deprecated since version 2.0
*/
function add(a: number, b: number): number {
return a + b;
}
/**
* JSDoc
*/
Storybook 7 Autodocs
export interface ButtonProps {
/**
* Is this the principal call to action on the page?
*/
primary?: Boolean;
/**
* What background color to use
*/
backgroundColor?: string;
/**
* How large should the button be?
*/
size?: "small" | "medium" | "large";
/**
* Button contents
*/
label: string;
/**
* Optional click handler
*/
onClick?: Function;
}
/**
* Primary UI component for user interaction
*/
export function Button({
primary = false,
backgroundColor,
size = "medium",
label
}: ButtonProps) {
/* implementation details here */
}
Storybook 7 Autodocs
// Button.stories.tsx
import type { Meta } from "@storybook/react";
import { Button } from "./Button";
const meta: Meta<typeof Button> = {
component: Button,
tags: ["autodocs"],
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: {
primary: true,
label: "Button",
},
};
export const Secondary: Story = {
args: {
...Primary.args,
primary: false,
},
};
Storybook 7 Autodocs
Storybook 7 Autodocs
type ColorOption = "brand" | "accent" | "alert" | "none";
export interface ButtonProps {
/**
* Is this the principal call to action on the page?
*/
primary: boolean;
/**
* What background color option to use
*/
backgroundColor?: ColorOption;
/**
* How large should the button be?
*/
size?: "small" | "medium" | "large";
/**
* Button contents
*/
label: string;
/**
* Optional click handler
*/
onClick?: Function;
}
/**
* Primary UI component for user interaction
*/
export function Button({
primary = false,
backgroundColor = 'none',
size = "medium",
label
}: ButtonProps) {
/* implementation details here */
}
Storybook 7 Autodocs
Can be enable globally
// .storybook/main.ts
import type { StorybookConfig } from '@storybook/your-framework';
const config: StorybookConfig = {
framework: '@storybook/your-framework',
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: ['@storybook/addon-essentials'],
docs: {
autodocs: 'tag',
defaultName: 'Documentation',
},
};
export default config;
Change the default template
{/* DocumentationTemplate.mdx */}
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks';
<Meta isTemplate />
<Title />
# Default implementation
<Primary />
## Inputs
The component accepts the following inputs (props):
<Controls />
---
## Additional variations
Listed below are additional variations of the component.
<Stories />
Change the default template
// .storybook/preview.jsx
import DocumentationTemplate from './DocumentationTemplate.mdx';
export default {
parameters: {
docs: {
page: DocumentationTemplate,
},
},
};
Custom Doc Blocks
// .storybook/blocks/StoryName.jsx
import { useOf } from '@storybook/blocks';
export const StoryName = ({ of }) => {
const resolvedOf = useOf(of || 'story', ['story', 'meta']);
switch (resolvedOf.type) {
case 'story': {
return <h1>{resolvedOf.story.name}</h1>;
}
case 'meta': {
return <h1>{resolvedOf.preparedMeta.title}</h1>;
}
}
return null;
};
{/* ButtonDocs.mdx */}
import { Meta } from '@storybook/blocks';
import { StoryName } from '../.storybook/blocks/StoryName';
import * as ButtonStories from './Button.stories';
<Meta of={ButtonStories} />
{/* renders "Secondary" */}
<StoryName of={ButtonStories.Secondary} />
{/* renders "Primary" */}
<StoryName />
{/* renders "Button" */}
<StoryName of={ButtonStories} />
- Reduced Manual Effort
- Accurate and up-to-date documentation
- Encourages documentation to be updated as part of the code review process
- User has access to the best documentation where they are at, not just in Storybook
Benefits of using JSDoc, TS, and StoryBook
Documenting Storybook with TS and JSDocs
By Justin Travis Waith-Mair
Documenting Storybook with TS and JSDocs
- 58