When to Use Client Components

Server Components fetch data. Client Components handle interactions. This split determines where in-between states live and how they're managed.

Server Components determine what loads—they're async, fetch data directly, and render on the server. Client Components handle how users interact—optimistic updates, pending indicators, form state, and event handlers.

Server Components: Data Fetching

Server Components can be async and fetch data directly. No loading state management—Suspense handles that:

async function BlogList() { const posts = await getPublishedPosts(); return posts.map(post => <Card key={post.slug}>{post.title}</Card>); }

This component has no 'use client'—it runs on the server, has direct database access, and streams HTML to the client.

Client Components: Interactions

Add 'use client' when you need React hooks, event handlers, or browser APIs:

'use client'; export function ArchiveButton({ slug, archived }) { return ( <form action={async () => { await toggleArchivePost(slug, !archived); }}> <button type="submit"> {archived ? 'Unarchive' : 'Archive'} </button> </form> ); }

This component uses a form action—it must be a Client Component because the action is defined inline.

CSS :has() for Parent Styling

Here's a powerful pattern: Server Components can style based on Client Component state using CSS :has() and the useFormStatus hook.

// Client Component shows pending via useFormStatus <form action={action}> <SubmitButton /> {/* Uses useFormStatus internally */} </form> // Server Component styles based on child state <Card className="has-[[data-pending]]:animate-pulse"> <ArchiveButton slug={post.slug} archived={post.archived} /> </Card>

Tailwind's has-[[data-pending]]: variant uses CSS :has([data-pending])—the Card can pulse during the action without becoming a Client Component itself.

The Leaf Principle

Keep Client Components at the leaves of your component tree:

ServerComponent (layout, data fetching) ├── ServerComponent (more layout) │ └── ClientComponent (button with pending state) └── ServerComponent (list rendering) └── ClientComponent (toggle with optimistic update)

Server Components handle layout and data; Client Components handle interactive in-between states. This maximizes server work and minimizes client JavaScript.

November 4, 2025Updated March 1, 2026316 words