13 KiB
React Documentation Patterns Reference
Comprehensive reference for React documentation patterns. Use this when writing or reviewing docs.
Document Templates
Learn Page Template (src/content/learn/)
---
title: Your Page Title
---
<Intro>
Opening paragraph introducing the topic. Use *italics* for new terms being defined. Keep it to 1-2 sentences that hook the reader.
</Intro>
<YouWillLearn>
* Bullet point of what reader will learn
* Another learning outcome
* Keep to 3-5 items
</YouWillLearn>
## First Section {/*first-section*/}
Content with <Sandpack> examples...
<Recap>
* Summary bullet of key point
* Another summary point
</Recap>
<Challenges>
#### Challenge Title {/*challenge-id*/}
Challenge description...
<Sandpack>
{/* problem code */}
</Sandpack>
<Solution>
Explanation and solution...
<Sandpack>
{/* solution code */}
</Sandpack>
</Solution>
</Challenges>
Reference Page Template (src/content/reference/)
---
title: hookName
---
<Intro>
`hookName` is a React Hook that lets you [brief description].
\`\`\`js
const result = hookName(arg)
\`\`\`
</Intro>
<InlineToc />
---
## Reference {/*reference*/}
### `hookName(arg)` {/*hookname*/}
Call `hookName` at the top level of your component to...
\`\`\`js
import { hookName } from 'react';
function MyComponent() {
const result = hookName(initialValue);
// ...
\`\`\`
[See more examples below.](#usage)
#### Parameters {/*parameters*/}
* `arg`: Description of the parameter.
#### Returns {/*returns*/}
Description of return value.
#### Caveats {/*caveats*/}
* Caveat about usage.
* Another important caveat.
---
## Usage {/*usage*/}
### Common Use Case {/*common-use-case*/}
Explanation with <Sandpack> examples...
---
## Troubleshooting {/*troubleshooting*/}
### Common Problem {/*common-problem*/}
How to solve it...
Tone & Voice Guidelines
Learn Pages
- Conversational, friendly
- Address the reader as "you"
- "Here's what that looks like..."
- "You might be wondering..."
- "Let's see how this works..."
Reference Pages
- Precise, technical
- Still use "you" but more direct
- "Call
useStateat the top level..." - "This Hook returns..."
Universal Rules
- Capitalize React terms: Hook, Effect, State, Context, Ref, Component, Transition
- Capitalize: Server Component, Client Component, Server Action, Error Boundary, Suspense
- Use proper product names: ESLint, TypeScript, JavaScript (not lowercase)
- Use bold for key concepts: state variable, event handler
- Use italics for new terms being defined: event handlers
- Avoid "simple", "easy", "just" - these can be dismissive
- Prefer concrete examples over abstract explanations
- No time estimates ("quick", "takes X minutes")
- Frame feature differences as "capabilities" not "advantages/disadvantages"
- Avoid passive voice and jargon
Avoiding Jargon
React docs explain technical concepts in plain language. Follow these patterns:
Don't use CS jargon without explanation:
-
❌ "State updates are atomic"
-
✅ "React waits until all state updates are done before re-rendering"
-
❌ "Components must be idempotent"
-
✅ "Given the same inputs, a component always returns the same output"
-
❌ "Rendering must be deterministic"
-
✅ "React expects the same inputs to produce the same result"
Terms to avoid or always explain:
- "atomic" → describe what actually happens (all-or-nothing, batched together)
- "idempotent" → "same inputs, same output"
- "deterministic" → "predictable", "same result every time"
- "memoize/memoization" → "remember the result", "skip recalculating"
- "referentially transparent" → avoid entirely, explain the behavior
- "invariant" → "rule that must always be true", "requirement"
- "reify" → avoid entirely, describe what's being created
Use analogies the docs already establish:
- Rendering = preparing food in a kitchen
- Committing = placing the order on the table
- Batching = waiter collecting the full order before going to kitchen
- State = snapshot/photograph at a moment in time
- Pure functions = math formulas (y = 2x always gives same result)
Pattern: Explain behavior, then name it
React waits until all code in the event handlers has run before
processing your state updates. This is called *batching*.
Not:
React uses batching to process state updates atomically.
Code Style Rules (Enforced in PR Review)
These rules are strictly enforced during PR review:
Component Definitions
// ✅ Correct - function declaration
function MyInput({ value, onChange, ref }) {
return <input value={value} onChange={onChange} ref={ref} />;
}
export default MyInput;
// 🚫 Wrong - arrow function for component
const MyInput = ({ value, onChange, ref }) => {
return <input value={value} onChange={onChange} ref={ref} />;
};
Event Handlers
// ✅ Correct - use 'e' for event parameter
<button onClick={(e) => e.preventDefault()}>
// 🚫 Wrong - using 'event' (can conflict with global)
<button onClick={(event) => event.preventDefault()}>
createRoot Pattern
// ✅ Correct - two lines
const root = createRoot(document.getElementById('root'));
root.render(<App />);
// 🚫 Wrong - chained
createRoot(document.getElementById('root')).render(<App />);
State vs Ref Decision
// ✅ Use ref when value is not used for rendering
const isMounted = useRef(false);
// 🚫 Don't use state if not rendering based on it
const [isMounted, setIsMounted] = useState(false); // triggers re-render
Hydration-Safe Code
// ✅ Correct - same output on server and client
function App() {
const [count, setCount] = useState(0);
return <div>{count}</div>;
}
// 🚫 Wrong - different output causes hydration mismatch
function App() {
const isClient = typeof window !== 'undefined';
return <div>{isClient ? 'Client' : 'Server'}</div>;
}
Line Length Guidelines
Keep lines short enough to avoid horizontal scrolling on small screens:
- Prose: ~80 characters
- Code: ~60-70 characters preferred
- If longer, break into multiple lines
Anti-Patterns to Avoid
| Pattern | Problem | Fix |
|---|---|---|
const Comp = () => {} |
Not standard for components | function Comp() {} |
onClick={(event) => ...} |
Conflicts with global | onClick={(e) => ...} |
useState for non-rendered values |
Unnecessary re-renders | Use useRef instead |
Reading window during render |
Hydration mismatch | Check in useEffect |
| Single-line if statements | Harder to read/debug | Use multiline with braces |
Chained createRoot().render() |
Less clear | Two separate statements |
//... without space |
Inconsistent style | Use // ... with space |
| Tabs for indentation | Inconsistent rendering | Use 2 spaces |
Deprecated ReactDOM.render |
Outdated API | Use createRoot |
| Fake package names | Confusing readers | Use './your-storage-layer' |
PropsWithChildren |
Outdated pattern | Use children?: React.ReactNode |
Missing key in lists |
Causes warnings | Always include key prop |
forwardRef and memo Patterns
forwardRef with Named Function
// ✅ Correct - named function for display name
const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} ref={ref} />;
});
// 🚫 Wrong - anonymous function
const MyInput = forwardRef((props, ref) => {
return <input {...props} ref={ref} />;
});
memo with Named Function
// ✅ Correct - preserves component name
const Greeting = memo(function Greeting({ name }) {
return <h1>Hello, {name}</h1>;
});
// 🚫 Wrong - loses component name in DevTools
const Greeting = memo(({ name }) => {
return <h1>Hello, {name}</h1>;
});
MDX Component Decision Tree
<Pitfall>
Use for: Common mistakes that cause bugs or unexpected behavior.
<Pitfall>
React components must start with a capital letter or they won't work!
</Pitfall>
<Note>
Use for: Important clarifications, conventions, or tips.
<Note>
The convention is to name state variables like `[something, setSomething]`.
</Note>
<DeepDive>
Use for: Optional deep technical content. Must have #### heading as first child.
<DeepDive>
#### Why does this work? {/*why-does-this-work*/}
Technical explanation that's optional for understanding the main concept...
</DeepDive>
<Sandpack>
Use for: Interactive code examples.
<Sandpack>
\`\`\`js
export default function App() {
return <h1>Hello</h1>;
}
\`\`\`
\`\`\`css
h1 { color: blue; }
\`\`\`
</Sandpack>
<Recipes>
Use for: Multiple related examples showing variations.
<Recipes titleText="Examples of useState" titleId="examples-basic">
#### Counter (number) {/*counter-number*/}
Description...
<Sandpack>
{/* code */}
</Sandpack>
<Solution />
#### Text field (string) {/*text-field-string*/}
Description...
<Sandpack>
{/* code */}
</Sandpack>
<Solution />
</Recipes>
<Challenges>
Use for: End-of-page exercises (Learn pages only).
<Challenges>
#### Fix the bug {/*fix-the-bug*/}
Problem description...
<Hint>
Optional hint text.
</Hint>
<Sandpack>
{/* problem code */}
</Sandpack>
<Solution>
Explanation...
<Sandpack>
{/* solution code */}
</Sandpack>
</Solution>
</Challenges>
Sandpack Patterns
Comprehensive guidelines: See
.claude/skills/docs-sandpack/SKILL.mdfor complete Sandpack patterns including package.json usage, hidden/active files, file structure, and code size limits.
Quick Reference
| Pattern | When to Use |
|---|---|
hidden |
package.json, data files, API mocks, infrastructure |
active |
File containing primary teaching concept |
| Single file | Basic hooks, simple concepts (70% of examples) |
| Multi-file | Imports, context, component reuse (30% of examples) |
File Naming
- Main file:
```js(no prefix) - Supporting files:
```js src/FileName.js - Active file (reference pages):
```js src/File.js active - Hidden files:
```js src/data.js hidden - CSS:
```css - Package.json (for dependencies):
```json package.json
Line Highlighting
\`\`\`js {2-4}
function Example() {
// These lines (2-4)
// will be
// highlighted
return null;
}
\`\`\`
Code References (for callouts)
\`\`\`js [[1, 4, "age"], [2, 4, "setAge"]]
// Creates numbered callouts pointing to specific code
\`\`\`
Expected Errors (for intentionally broken examples)
\`\`\`js {expectedErrors: {'react-compiler': [7]}}
// Line 7 will show as expected error
\`\`\`
Multiple Files
<Sandpack>
\`\`\`js src/App.js
import Gallery from './Gallery.js';
export default function App() {
return <Gallery />;
}
\`\`\`
\`\`\`js src/Gallery.js
export default function Gallery() {
return <h1>Gallery</h1>;
}
\`\`\`
\`\`\`css
h1 { color: purple; }
\`\`\`
</Sandpack>
External Dependencies
<Sandpack>
\`\`\`js
import { useImmer } from 'use-immer';
// ...
\`\`\`
\`\`\`json package.json
{
"dependencies": {
"immer": "1.7.3",
"use-immer": "0.5.1",
"react": "latest",
"react-dom": "latest",
"react-scripts": "latest"
}
}
\`\`\`
</Sandpack>
Common Patterns
Showing Wrong vs Right Code
\`\`\`js
// 🚩 Don't mutate state like this:
obj.x = 10;
setObj(obj);
\`\`\`
\`\`\`js
// ✅ Replace state with a new object:
setObj({
...obj,
x: 10
});
\`\`\`
Table Comparisons
| passing a function (correct) | calling a function (incorrect) |
| -------------------------------- | ---------------------------------- |
| `<button onClick={handleClick}>` | `<button onClick={handleClick()}>` |
Linking to Other Pages
[Read more about state](/learn/state-a-components-memory)
[See the `useState` reference](/reference/react/useState)
Inline Code Annotations
Use <CodeStep> for numbered callouts in prose:
The <CodeStep step={1}>current state</CodeStep> is initially set to the <CodeStep step={3}>initial state</CodeStep> you provided.
Troubleshooting Sections
Error headings must follow this format:
### I'm getting an error: "Too many re-renders" {/*too-many-re-renders*/}
This error usually means...
Not:
### Too many re-renders error {/*too-many-re-renders*/}
Blog Post Guidelines
Updating Old Blog Posts
- Never break existing links; add redirects when URLs change
- Do not rewrite history; add update notes with dates instead of replacing text
- Use format:
**Update (Month Year):** New information here.
Announcing Features
- Do not promise or oversell features that are not yet available
- If a feature is "upcoming," say so explicitly
- Include FAQ sections for anticipated developer questions
- Focus on correctness over marketing language
React 19+ Documentation Patterns
Documenting API Changes
When APIs change between versions, document both patterns:
Starting in React 19, you can render `<SomeContext>` as a provider:
\`\`\`js
<SomeContext value={value}>
{children}
</SomeContext>
\`\`\`
In older versions of React, use `<SomeContext.Provider>`:
\`\`\`js
<SomeContext.Provider value={value}>
{children}
</SomeContext.Provider>
\`\`\`
Version Notes
- Use "Starting in React 19..." for new patterns
- Use "In older versions of React..." for legacy patterns
- Add version badges where appropriate