.config/opencode/skills/react-use-client-boundary/SKILL.md
Guides proper usage of "use client" directive in React/Next.js. Use this skill when adding client components, troubleshooting Server Component errors, or deciding where to place the client boundary.
npx skillsauth add klen/dotfiles react-use-client-boundaryInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Understanding when to use (and when NOT to use) the "use client" directive in React Server Components architecture.
"use client" marks a boundary between server and client components - not a label
for individual components.
Critical Rule: Once inside a client boundary,
ALL imported components are automatically client components.
You should NOT add "use client" to child components
that are already imported by a parent client component.
Think of "use client" as a fence or gate:
┌─────────────────────────────────────────────────────┐
│ SERVER TERRITORY │
│ ┌─────────────┐ │
│ │ page.tsx │ (Server Component - default) │
│ │ │ │
│ │ <Header /> │───────────────────────┐ │
│ └─────────────┘ │ │
│ ▼ │
│ ════════════════ "use client" FENCE ════════════ │
│ │ │
│ ┌─────────────────────────────────────┼──────────┐ │
│ │ CLIENT TERRITORY ▼ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Header.tsx │───▶│ NavMenu.tsx │ │ │
│ │ │"use client" │ │ (no directive│ │ │
│ │ │ │ │ needed!) │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ You're already inside - no more fences needed │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Add the directive when ALL of these are true:
useState, useEffect, useContext, etc.)onClick, onChange, onSubmit, etc.)window, document, localStorage, etc.)"use client"// ❌ WRONG: Unnecessary "use client" in child
// components/form.tsx
"use client"
import { Input } from "./input"
import { Button } from "./button"
export function Form() {
const [value, setValue] = useState("")
return (
<form>
<Input value={value} onChange={setValue} />
<Button type="submit">Send</Button>
</form>
)
}
// components/input.tsx
"use client" // ❌ WRONG - already a client component!
export function Input({ value, onChange }) {
return <input value={value} onChange={e => onChange(e.target.value)} />
}
// components/button.tsx
"use client" // ❌ WRONG - already a client component!
export function Button({ children, type }) {
return <button type={type}>{children}</button>
}
// ✅ CORRECT: Only the entry point has "use client"
// components/form.tsx
"use client"
import { Input } from "./input"
import { Button } from "./button"
export function Form() {
const [value, setValue] = useState("")
return (
<form>
<Input value={value} onChange={setValue} />
<Button type="submit">Send</Button>
</form>
)
}
// components/input.tsx
// ✅ No directive - imported by client component
export function Input({ value, onChange }) {
return <input value={value} onChange={e => onChange(e.target.value)} />
}
// components/button.tsx
// ✅ No directive - imported by client component
export function Button({ children, type }) {
return <button type={type}>{children}</button>
}
Is this component imported by a Server Component?
│
├─ NO ──▶ Is its parent/importer a Client Component?
│ │
│ ├─ YES ──▶ ❌ Don't add "use client" (already in boundary)
│ │
│ └─ NO ───▶ Check the import chain upward
│
└─ YES ─▶ Does this component need client features?
│
├─ NO ──▶ ❌ Don't add "use client" (keep it server)
│
└─ YES ─▶ ✅ Add "use client" (create boundary here)
// app/products/page.tsx (Server Component - no directive)
import { ProductList } from "@/components/product-list"
import { SearchFilters } from "@/components/search-filters"
import { getProducts } from "@/lib/api"
export default async function ProductsPage() {
const products = await getProducts() // Server-side data fetching
return (
<main>
<h1>Products</h1>
<SearchFilters /> {/* Client boundary starts here */}
<ProductList data={products} /> {/* Server component */}
</main>
)
}
// components/search-filters.tsx
"use client" // ✅ Boundary: imported by server, needs state
import { FilterDropdown } from "./filter-dropdown"
import { PriceSlider } from "./price-slider"
export function SearchFilters() {
const [filters, setFilters] = useState({})
return (
<div>
<FilterDropdown onSelect={...} /> {/* No directive needed */}
<PriceSlider onChange={...} /> {/* No directive needed */}
</div>
)
}
// components/filter-dropdown.tsx
// ✅ No "use client" - already inside client boundary
export function FilterDropdown({ onSelect }) {
return <select onChange={e => onSelect(e.target.value)}>...</select>
}
// components/price-slider.tsx
// ✅ No "use client" - already inside client boundary
export function PriceSlider({ onChange }) {
return <input type="range" onChange={e => onChange(e.target.value)} />
}
When a component is used by BOTH server and client components:
// components/card.tsx
// No directive - works in both contexts if it's pure presentation
export function Card({ title, children }) {
return (
<div className="card">
<h2>{title}</h2>
{children}
</div>
)
}
// app/page.tsx (Server Component)
import { Card } from "@/components/card"
// Card renders as server component here
// components/modal.tsx
"use client"
import { Card } from "@/components/card"
// Card renders as client component here (inside boundary)
Cause: Using hooks in a component without "use client" that's imported by a server component.
Fix: Add "use client" to the component using the hook,
OR move the hook usage to a parent client component.
Cause: Trying to pass a function from server to client component.
Fix: Move the event handler logic to the client component, or restructure the boundary.
Cause: Using async component syntax inside a client boundary.
Fix: Keep data fetching in server components, pass data as props to client components.
| Do | Don't |
|---|---|
| Place "use client" at the highest necessary point | Sprinkle "use client" on every component |
| Keep the client boundary as small as possible | Make entire pages client components |
| Let child components inherit client context | Add redundant "use client" to children |
| Use server components for data fetching | Fetch data in client components when avoidable |
tools
Anti-patterns and mistakes to avoid as a product manager. Use when evaluating leadership behaviors, improving team dynamics, reflecting on management practices, or onboarding new product managers.
development
Guides proper usage of TypeScript's satisfies operator vs type annotations. Use this skill when deciding between type annotations (colon) and satisfies, validating object shapes while preserving literal types, or troubleshooting type inference issues.
development
Guides when to use interface vs type in TypeScript. Use this skill when defining object types, extending types, or choosing between interface and type aliases.
development
Guides TypeScript best practices for type safety, code organization, and maintainability. Use this skill when configuring TypeScript projects, deciding on typing strategies, writing async code, or reviewing TypeScript code quality.