Claude-skill-registry docs-sandpack
Use when adding interactive code examples to React docs.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/docs-sandpack" ~/.claude/skills/majiayu000-claude-skill-registry-docs-sandpack && rm -rf "$T"
manifest:
skills/data/docs-sandpack/SKILL.mdsource content
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 |
|---|---|
| Main file (no prefix) |
| Supporting files |
| Active file (reference pages) |
| Hidden files |
| CSS styles |
| 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>; }
</Sandpack> ```h1 { color: purple; }
External Dependencies
<Sandpack> ```js import { useImmer } from 'use-immer'; // ...
</Sandpack> ```{ "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:
- Function declarations for components (not arrows)
for event parameterse- Single quotes in JSX
unless reassignment neededconst- Spaces in destructuring:
not({ props })({props}) - Two-line createRoot: separate declaration and render call
- 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 |
|---|---|---|
| Not standard | |
| Conflicts with global | |
for non-rendered values | Re-renders | Use |
Reading during render | Hydration mismatch | Check in useEffect |
| Single-line if without braces | Harder to debug | Use multiline with braces |
Chained | Less clear | Two statements |
without space | Inconsistent | with space |
| Tabs | Inconsistent | 2 spaces |
| Deprecated | Use |
| Fake package names | Confusing | Use |
| Outdated | |
Missing 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:
notGallery.jsgallery.js - After initially explaining files are in
, refer to files by name only:src/
notGallery.jssrc/Gallery.js
Naming Conventions in Code
Components: PascalCase
,Profile
,Avatar
,TodoListPackingList
State variables: Destructured pattern
const [count, setCount] = useState(0)- Booleans:
,[isOnline, setIsOnline][isPacked, setIsPacked] - Status strings:
,'typing'
,'submitting'
,'success''error'
Event handlers:
,handleClick
,handleSubmithandleAddTask
Props for callbacks:
,onClick
,onChange
,onAddTaskonSelect
Custom Hooks:
,useOnlineStatus
,useChatRoomuseFormInput
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