react-use-client-boundary

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.

210 stars

Best use case

react-use-client-boundary is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

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.

Teams using react-use-client-boundary should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/react-use-client-boundary/SKILL.md --create-dirs "https://raw.githubusercontent.com/flpbalada/my-opencode-config/main/skills/react-use-client-boundary/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/react-use-client-boundary/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How react-use-client-boundary Compares

Feature / Agentreact-use-client-boundaryStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

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.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# React "use client" Directive & Client Boundaries

Understanding when to use (and when NOT to use) the "use client" directive in React Server Components architecture.

## Core Concept: The Boundary

`"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.

## Mental Model: The Fence

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 │ │
│  └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```

## When to Use "use client"

Add the directive when ALL of these are true:

1. **The component is imported by a Server Component** (directly or as a page entry)
2. **AND** the component needs client-side features:
   - React hooks (`useState`, `useEffect`, `useContext`, etc.)
   - Event handlers (`onClick`, `onChange`, `onSubmit`, etc.)
   - Browser APIs (`window`, `document`, `localStorage`, etc.)
   - Third-party libraries that use any of the above

## When NOT to Use "use client"

1. **Already inside a client boundary** - parent component has `"use client"`
2. **Component is pure presentation** - just renders props, no interactivity
3. **"Just to be safe"** - this creates confusion and unnecessary boundaries
4. **Every component that uses props** - props work fine in server components

## Common Mistake: Redundant Directives

```tsx
// ❌ 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 Approach: Single Boundary

```tsx
// ✅ 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>
}
```

## Decision Flowchart

```
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)
```

## Real-World Example: Page with Interactive Section

```tsx
// 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)} />
}
```

## Edge Case: Shared Components

When a component is used by BOTH server and client components:

```tsx
// 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)
```

## Troubleshooting Common Errors

### Error: "useState only works in Client Components"

**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.

### Error: "Event handlers cannot be passed to Client Components from Server Components"

**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.

### Error: "async/await is not yet supported in Client Components"

**Cause:** Using async component syntax inside a client boundary.

**Fix:** Keep data fetching in server components, pass data as props to client components.

## Best Practices Summary

| 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 |

## References

- [React Docs: "use client"](https://react.dev/reference/rsc/use-client)
- [Next.js Discussion: Client Component Boundaries](https://github.com/vercel/next.js/discussions/46795)

Related Skills

react-useeffect-avoid

210
from flpbalada/my-opencode-config

Guides when NOT to use useEffect and suggests better alternatives. Use when reviewing React code, troubleshooting performance, or considering useEffect for derived state or form resets.

react-use-state

210
from flpbalada/my-opencode-config

Guides proper usage of React useState hook. Use this skill when adding state to components, deciding between useState vs alternatives, or troubleshooting state update issues.

react-use-callback

210
from flpbalada/my-opencode-config

Guides proper usage of the useCallback hook in React. Use this skill when optimizing function references, passing callbacks to memoized components, or preventing unnecessary re-renders.

react-key-prop

210
from flpbalada/my-opencode-config

Guides proper usage of the key prop in React lists. Use this skill when rendering lists, mapping arrays to components, or troubleshooting list-related state bugs.

what-not-to-do-as-product-manager

210
from flpbalada/my-opencode-config

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.

visual-cues-cta-psychology

210
from flpbalada/my-opencode-config

Design effective CTAs using visual attention and gaze psychology principles. Use when designing landing pages, button hierarchies, conversion elements, or optimizing user attention flow through interfaces.

vercel-sandbox

210
from flpbalada/my-opencode-config

Run agent-browser + Chrome inside Vercel Sandbox microVMs for browser automation from any Vercel-deployed app. Use when the user needs browser automation in a Vercel app (Next.js, SvelteKit, Nuxt, Remix, Astro, etc.), wants to run headless Chrome without binary size limits, needs persistent browser sessions across commands, or wants ephemeral isolated browser environments. Triggers include "Vercel Sandbox browser", "microVM Chrome", "agent-browser in sandbox", "browser automation on Vercel", or any task requiring Chrome in a Vercel Sandbox.

value-realization

210
from flpbalada/my-opencode-config

Analyze if end users discover clear value. Use when evaluating product concepts, analyzing adoption, or uncertain about direction.

user-story-fundamentals

210
from flpbalada/my-opencode-config

Capture requirements from user perspective with structured user stories. Use when writing backlog items, defining acceptance criteria, prioritizing features, or communicating requirements between product and development.

typescript-satisfies-operator

210
from flpbalada/my-opencode-config

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.

typescript-interface-vs-type

210
from flpbalada/my-opencode-config

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.

typescript-best-practices

210
from flpbalada/my-opencode-config

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.