← Back
Edit Post
Title
Description
Server vs Client Components, CSS :has() for parent styling, leaf principle.
Content
Markdown supported
# 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: ```tsx 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: ```tsx '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. ```tsx // 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: ```text 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.
Published
Save Changes
Cancel