React Stencil is a tool to help you create functioning component documentation for use internally for design and development or externally as a part of a wider design system for all to use.
It provides a higher order function that will wrap a React component and render component documentation with various information.
npm install react-stencil --save
So our project has a button component:
import React from 'react'
import PropTypes from 'prop-types'
export default function Button (props) {
return (
<button
id={props.id}
onClick={props.onClick}>
{props.children}
</button>
)
}
Button.propTypes = {
onClick: PropTypes.func.isRequired,
children: PropTypes.string.isRequired,
id: PropTypes.string
}
We can create a new component that documents the button by wrapping <Button />
using the stencil
higher order function.
import stencil from 'react-stencil'
import Button from 'button'
export default stencil({})(Button)
With this new component you can render it as you wish. With React Stencil I have set out to make it un-opinionated in how you choose to display it.
You show additional details about the component by passing some information and we can do this by passing a 'spec'.
There is a separate tool which will do some automation for you. Take a look at the documentation for React Stencil CLI.
For now, let's do a little manual speccing and continue to document our <Button />
component.
import React from 'react'
import stencil from 'react-stencil'
import Button from 'button'
const spec = {
name: 'Button',
description: 'A button that takes an action',
swatches: ['red', 'black', '#d73a49'],
status: 'READY',
props: {
id: {
type: 'string',
required: false,
description: 'A unique ID'
},
warning: {
type: 'bool',
required: false,
description: 'Should this button be shown as a warning button'
}
children: {
type: 'string',
required: true,
description: 'Copy to be shown in the button'
},
onClick: {
type: 'func',
required: true,
description: 'An action to fire when the button is clicked'
}
},
examples: {
'Warning': {
id: 'warning-button'
warning: true,
children: 'I am a dangerous action!'
}
},
notes: {
'do\'s & dont\'s': (
<ul
className="guide">
<li
className="guide__good">
Do use a Button to fire an action
</li>
<li
className="guide__bad">
Don't use a Button to link to another page
</li>
</ul>
)
}
}
export default stencil(spec)(Button)
Here's a breakdown of what the spec means and what can be generated by React Stencil CLI.
Can be generated by React Stencil CLI
The name of the component that is being documented.
Can be generated by React Stencil CLI
A space dedicated to describing what the component is or does, perhaps even why it was created to begin with.
Swatches are colours that you can switch out the background of the preview panel. By default the documented component will have a semi transparent background.
Give a status to the component on whether it is production ready, currently being worked on or is not ready to be used by others.
The constants are 'READY', 'WIP' and 'DANGEROUS'.
Can be generated by React Stencil CLI
A list of the all the props the component accepts keyed by the name of the prop.
- Type is the type given to the prop and should be based on React's PropTypes.
- Required is whether the prop is required or not.
- defaultValue is the initial value that the component has set on it.
- description can be used to document what the prop does or how it can be used.
You can provide props to build examples. Choosing an example will update the preview with those props allowing users to see how a component can/should be used.
Notes can be used to further document the component. It's an object and each key will give you a new header while the value is the documentation itself. You can pass strings or components affording you the option to document in any way you feel appropriate.
Specifying descriptions per prop per component would become tedious. For example, onClick; It's likely to be widely used in components but how to describe what it is and how to use it is unlikely to change between components.
For instances like this we can define a global spec. The global spec can then be merged with an individual component spec, hopefully saving you valuable time documenting.
To do this we'll use Stencil's merge helper. As a note, any definitions that are included in the component spec will overwrite the global spec meaning that if you wish to have a component specific description or set of swatches you can.
Here's an example:
// specs/global-spec.js
export default {
props: {
onClick: {
description: 'An action to fire when the button is clicked'
}
},
swatches: ['red', 'black', '#d73a49']
}
// specs/components/button.js
import stencil, { merge } from 'react-stencil'
import globalSpec from '../../global-spec'
import Button from 'button'
const buttonSpec = {
// a whole bunch of button specs
}
const spec = merge(globalSpec, buttonSpec)
export default stencil(spec)(Button)