How to document components in React
Documenting React components is a critical task that ensures your codebase remains maintainable, scalable, and accessible to other developers. With over 25 years of experience in software development and as the creator of CoreUI, I’ve built and documented hundreds of complex components for millions of users worldwide. From my expertise, the most efficient approach is a multi-layered strategy combining JSDoc for inline descriptions, TypeScript for structural type safety, and Storybook for visual documentation. This combination provides immediate feedback in modern IDEs and creates a live style guide for your entire design system.
Use JSDoc comments for descriptive metadata and TypeScript interfaces to define the structural contract of your React components.
Section 1: Documenting with JSDoc
JSDoc is the industry standard for adding descriptive comments to JavaScript code, providing hover information and autocomplete suggestions directly in editors like VS Code.
import React from 'react'
/**
* A reusable Button component that supports various themes and sizes.
* Use this component for primary user actions throughout the application.
*
* @param {Object} props - The properties passed to the component.
* @param {string} props.color - The background color theme (e.g., 'primary', 'success').
* @param {boolean} [props.disabled=false] - If true, the button will be non-interactive.
* @param {React.ReactNode} props.children - The content to be rendered inside the button.
* @returns {JSX.Element} The rendered button component.
*/
const CustomButton = ({ color, disabled, children }) => {
return (
<button
className={`btn btn-${color}`}
disabled={disabled}
>
{children}
</button>
)
}
export default CustomButton
In this example, the block comment starting with /** allows tools to parse the description and parameters. This is the same method we use in CoreUI Buttons to ensure every prop is clearly explained to the developer.
Section 2: Using TypeScript for Self-Documenting Code
TypeScript is the most powerful tool for documenting React components because it enforces the documentation at compile-time, preventing mismatched props and types.
import React from 'react'
interface AlertProps {
/** The message to display inside the alert box */
message: string
/**
* The visual style of the alert.
* @default 'info'
*/
variant?: 'success' | 'danger' | 'warning' | 'info'
/** Optional callback triggered when the user closes the alert */
onClose?: () => void
}
/**
* Alert component used to provide feedback to the user.
* It supports multiple variants to indicate the nature of the message.
*/
const Alert: React.FC<AlertProps> = ({ message, variant = 'info', onClose }) => {
return (
<div className={`alert alert-${variant}`}>
{message}
{onClose && <button onClick={onClose}>×</button>}
</div>
)
}
export default Alert
By defining an interface or type, you create a formal contract. IDEs will automatically show the comments added inside the interface when you hover over the prop names in your JSX code. This reduces the need to switch between files to understand how a component works.
Section 3: Visual Documentation with Storybook
Storybook allows you to document components in isolation, creating a visual catalog where developers can interact with different states and edge cases.
import CustomButton from './CustomButton'
export default {
title: 'Components/CustomButton',
component: CustomButton,
argTypes: {
color: { control: 'color' },
disabled: { control: 'boolean' },
},
}
export const Primary = {
args: {
color: 'primary',
children: 'Click Me',
},
}
export const Disabled = {
args: {
color: 'secondary',
disabled: true,
children: 'Locked',
},
}
Storybook serves as a “live” documentation site. It’s particularly useful for complex elements like CoreUI Modals, where you need to see how the component behaves in different viewports and configurations without running the entire application.
Section 4: Documenting Component Hooks
When creating custom hooks for your components, documenting the return values and input parameters is essential for clarity and reuse.
import { useState, useCallback } from 'react'
/**
* Custom hook to manage the toggle state of UI elements like Modals or Dropdowns.
*
* @param {boolean} initialState - The starting visibility state.
* @returns {[boolean, () => void]} A tuple containing the visibility state and a toggle function.
*/
export const useToggle = (initialState: boolean = false): [boolean, () => void] => {
const [isOpen, setIsOpen] = useState(initialState)
const toggle = useCallback(() => {
setIsOpen((prev) => !prev)
}, [])
return [isOpen, toggle]
}
Documenting hooks ensures that utility logic remains transparent. For instance, if you are building a component that needs to format a number as currency, documenting the transformation logic inside the hook prevents bugs and duplicate code.
Section 5: README Files for High-Level Overview
Every complex component or component folder should have a README.md to explain the “Why” and provide quick-start examples that code comments might not cover effectively.
# SmartTable Component
The `SmartTable` is a data-grid component designed for large datasets.
It supports sorting, filtering, and pagination out of the box.
## Installation
```bash
npm install @coreui/react-pro
Basic Usage
import { CSmartTable } from '@coreui/react-pro'
const MyPage = () => (
<CSmartTable
items={items}
columns={['name', 'email', 'status']}
/>
)
Internal References
- For data formatting, see how to convert an array to a string.
- Check our Table Documentation for advanced styling.
Markdown files are the best place for architectural notes, installation instructions, and linking to related utilities. This structured approach is what makes our [Admin Dashboard Template](/product/admin-dashboard-template/) so easy for teams to adopt quickly.
## Section 6: PropTypes for Runtime Validation
While TypeScript handles compile-time checks, PropTypes provide runtime warnings in the browser console, which is helpful during development for teams not using TypeScript.
```jsx
import React from 'react'
import PropTypes from 'prop-types'
const Badge = ({ children, color }) => (
<span className={`badge bg-${color}`}>
{children}
</span>
)
Badge.propTypes = {
/** The content of the badge */
children: PropTypes.node.isRequired,
/** The background color variant */
color: PropTypes.oneOf(['primary', 'secondary', 'success', 'danger', 'info', 'light', 'dark']),
}
Badge.defaultProps = {
color: 'primary',
}
export default Badge
PropTypes act as a living documentation of your component’s expectations. If a developer passes a number where a string is expected, the browser console will provide a clear error message, making debugging significantly faster.
Best Practice Note:
Consistency is more important than the specific tool you choose. At CoreUI, we recommend using TypeScript as your primary documentation source because it provides the most “bang for your buck” by combining types and documentation into a single source of truth. Always include a short JSDoc description for exported components to help your team understand the intent behind the code without having to read the implementation details.



