Files
react.dev/.claude/skills/docs-sandpack/SKILL.md
Ricky 38b52cfdf0 More claude stuff (#8280)
* More claude stuff

* more stuff from uee edit

* revert
2026-01-30 14:54:45 -05:00

10 KiB

name, description
name description
docs-sandpack Use when adding interactive code examples to React docs.

Sandpack Patterns

Quick Start Template

Most examples are single-file. Copy this and modify:

<Sandpack>

` ` `js
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState(0);

  return (
    <button onClick={() => setValue(value + 1)}>
      Clicked {value} times
    </button>
  );
}
` ` `

</Sandpack>

File Naming

Pattern Usage
```js Main file (no prefix)
```js src/FileName.js Supporting files
```js src/File.js active Active file (reference pages)
```js src/data.js hidden Hidden files
```css CSS styles
```json package.json External dependencies

Critical: Main file must have export default.

Line Highlighting

```js {2-4}
function Example() {
  // Lines 2-4
  // will be
  // highlighted
  return null;
}

Code References (numbered callouts)

```js [[1, 4, "age"], [2, 4, "setAge"]]
// Creates numbered markers pointing to "age" and "setAge" on line 4

Expected Errors (intentionally broken examples)

```js {expectedErrors: {'react-compiler': [7]}}
// Line 7 shows as expected error

Multi-File Example

<Sandpack>

```js src/App.js
import Gallery from './Gallery.js';

export default function App() {
  return <Gallery />;
}
export default function Gallery() {
  return <h1>Gallery</h1>;
}
h1 { color: purple; }
```

External Dependencies

<Sandpack>

```js
import { useImmer } from 'use-immer';
// ...
{
  "dependencies": {
    "immer": "1.7.3",
    "use-immer": "0.5.1",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest"
  }
}
```

Code Style in Sandpack (Required)

Sandpack examples are held to strict code style standards:

  1. Function declarations for components (not arrows)
  2. e for event parameters
  3. Single quotes in JSX
  4. const unless reassignment needed
  5. Spaces in destructuring: ({ props }) not ({props})
  6. Two-line createRoot: separate declaration and render call
  7. Multiline if statements: always use braces

Don't Create Hydration Mismatches

Sandpack examples must produce the same output on server and client:

// 🚫 This will cause hydration warnings
export default function App() {
  const isClient = typeof window !== 'undefined';
  return <div>{isClient ? 'Client' : 'Server'}</div>;
}

Use Ref for Non-Rendered State

// 🚫 Don't trigger re-renders for non-visual state
const [mounted, setMounted] = useState(false);
useEffect(() => { setMounted(true); }, []);

// ✅ Use ref instead
const mounted = useRef(false);
useEffect(() => { mounted.current = true; }, []);

forwardRef and memo Patterns

forwardRef - Use Named Function

// ✅ Named function for DevTools display name
const MyInput = forwardRef(function MyInput(props, ref) {
  return <input {...props} ref={ref} />;
});

// 🚫 Anonymous loses name
const MyInput = forwardRef((props, ref) => { ... });

memo - Use Named Function

// ✅ Preserves component name
const Greeting = memo(function Greeting({ name }) {
  return <h1>Hello, {name}</h1>;
});

Line Length

  • Prose: ~80 characters
  • Code: ~60-70 characters
  • Break long lines to avoid horizontal scrolling

Anti-Patterns

Pattern Problem Fix
const Comp = () => {} Not standard function Comp() {}
onClick={(event) => ...} Conflicts with global onClick={(e) => ...}
useState for non-rendered values Re-renders Use useRef
Reading window during render Hydration mismatch Check in useEffect
Single-line if without braces Harder to debug Use multiline with braces
Chained createRoot().render() Less clear Two statements
//... without space Inconsistent // ... with space
Tabs Inconsistent 2 spaces
ReactDOM.render Deprecated Use createRoot
Fake package names Confusing Use './your-storage-layer'
PropsWithChildren Outdated children?: ReactNode
Missing key in lists Warnings Always include key

Additional Code Quality Rules

Always Include Keys in Lists

// ✅ Correct
{items.map(item => <li key={item.id}>{item.name}</li>)}

// 🚫 Wrong - missing key
{items.map(item => <li>{item.name}</li>)}

Use Realistic Import Paths

// ✅ Correct - descriptive path
import { fetchData } from './your-data-layer';

// 🚫 Wrong - looks like a real npm package
import { fetchData } from 'cool-data-lib';

Console.log Labels

// ✅ Correct - labeled for clarity
console.log('User:', user);
console.log('Component Stack:', errorInfo.componentStack);

// 🚫 Wrong - unlabeled
console.log(user);

Keep Delays Reasonable

// ✅ Correct - 1-1.5 seconds
setTimeout(() => setLoading(false), 1000);

// 🚫 Wrong - too long, feels sluggish
setTimeout(() => setLoading(false), 3000);

Updating Line Highlights

When modifying code in examples with line highlights ({2-4}), always update the highlight line numbers to match the new code. Incorrect line numbers cause rendering crashes.

File Name Conventions

  • Capitalize file names for component files: Gallery.js not gallery.js
  • After initially explaining files are in src/, refer to files by name only: Gallery.js not src/Gallery.js

Naming Conventions in Code

Components: PascalCase

  • Profile, Avatar, TodoList, PackingList

State variables: Destructured pattern

  • const [count, setCount] = useState(0)
  • Booleans: [isOnline, setIsOnline], [isPacked, setIsPacked]
  • Status strings: 'typing', 'submitting', 'success', 'error'

Event handlers:

  • handleClick, handleSubmit, handleAddTask

Props for callbacks:

  • onClick, onChange, onAddTask, onSelect

Custom Hooks:

  • useOnlineStatus, useChatRoom, useFormInput

Reducer actions:

  • Past tense: 'added', 'changed', 'deleted'
  • Snake_case compounds: 'changed_selection', 'sent_message'

Updater functions: Single letter

  • setCount(n => n + 1)

Pedagogical Code Markers

Wrong vs right code:

// 🔴 Avoid: redundant state and unnecessary Effect
// ✅ Good: calculated during rendering

Console.log for lifecycle teaching:

console.log('✅ Connecting...');
console.log('❌ Disconnected.');

Server/Client Labeling

// Server Component
async function Notes() {
  const notes = await db.notes.getAll();
}

// Client Component
"use client"
export default function Expandable({children}) {
  const [expanded, setExpanded] = useState(false);
}

Bundle Size Annotations

import marked from 'marked'; // 35.9K (11.2K gzipped)
import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)

Sandpack Example Guidelines

Package.json Rules

Include package.json when:

  • Using external npm packages (immer, remarkable, leaflet, toastify-js, etc.)
  • Demonstrating experimental/canary React features
  • Requiring specific React versions (react: beta, react: 19.0.0-rc-*)

Omit package.json when:

  • Example uses only built-in React features
  • No external dependencies needed
  • Teaching basic hooks, state, or components

Always mark package.json as hidden:

```json package.json hidden
{
  "dependencies": {
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "immer": "1.7.3"
  }
}

**Version conventions:**
- Use `"latest"` for stable features
- Use exact versions only when compatibility requires it
- Include minimal dependencies (just what the example needs)

### Hidden File Patterns

**Always hide these file types:**

| File Type | Reason |
|-----------|--------|
| `package.json` | Configuration not the teaching point |
| `sandbox.config.json` | Sandbox setup is boilerplate |
| `public/index.html` | HTML structure not the focus |
| `src/data.js` | When it contains sample/mock data |
| `src/api.js` | When showing API usage, not implementation |
| `src/styles.css` | When styling is not the lesson |
| `src/router.js` | Supporting infrastructure |
| `src/actions.js` | Server action implementation details |

**Rationale:**
- Reduces cognitive load
- Keeps focus on the primary concept
- Creates cleaner, more focused examples

**Example:**
```mdx
```js src/data.js hidden
export const items = [
  { id: 1, name: 'Item 1' },
  { id: 2, name: 'Item 2' },
];

### Active File Patterns

**Mark as active when:**
- File contains the primary teaching concept
- Learner should focus on this code first
- Component demonstrates the hook/pattern being taught

**Effect of the `active` marker:**
- Sets initial editor tab focus when Sandpack loads
- Signals "this is what you should study"
- Works with hidden files to create focused examples

**Most common active file:** `src/index.js` or `src/App.js`

**Example:**
```mdx
```js src/App.js active
// This file will be focused when example loads
export default function App() {
  // ...
}

### File Structure Guidelines

| Scenario | Structure | Reason |
|----------|-----------|--------|
| Basic hook usage | Single file | Simple, focused |
| Teaching imports | 2-3 files | Shows modularity |
| Context patterns | 4-5 files | Realistic structure |
| Complex state | 3+ files | Separation of concerns |

**Single File Examples (70% of cases):**
- Use for simple concepts
- 50-200 lines typical
- Best for: Counter, text inputs, basic hooks

**Multi-File Examples (30% of cases):**
- Use when teaching modularity/imports
- Use for context patterns (4-5 files)
- Use when component is reused

**File Naming:**
- Main component: `App.js` (capitalized)
- Component files: `Gallery.js`, `Button.js` (capitalized)
- Data files: `data.js` (lowercase)
- Utility files: `utils.js` (lowercase)
- Context files: `TasksContext.js` (named after what they provide)

### Code Size Limits

- Single file: **<200 lines**
- Multi-file total: **150-300 lines**
- Main component: **100-150 lines**
- Supporting files: **20-40 lines each**

### CSS Guidelines

**Always:**
- Include minimal CSS for demo interactivity
- Use semantic class names (`.panel`, `.button-primary`, `.panel-dark`)
- Support light/dark themes when showing UI concepts
- Keep CSS visible (never hidden)

**Size Guidelines:**
- Minimal (5-10 lines): Basic button styling, spacing
- Medium (15-30 lines): Panel styling, form layouts
- Complex (40+ lines): Only for layout-focused examples