GuideEdit this page.md

Client components

When you need interactivity on the client side, you can use client components. Client components will be also rendered on the server side, but the client component will be hydrated on the client side.

All client components will be loaded asynchronously, so they will not block the rendering of the page. All client component will be compiled into an ES module and get lazy loaded only when needed.

To create a client component, add the "use client"; pragma at the top of the file.

"use client"; export default function MyClientComponent() { return <p>This is a client component</p>; }

Client components can use any React hooks, like the useState hook and can attach event handlers to elements like onClick. The client components are rendered both on the server side and on the client side.

"use client"; import { useState } from "react"; export default function Counter() { const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }

Client components can receive props from server components. The props will get serialized and passed to the client. All props passed to a client component must be serializable. You can pass any primitive values, arrays and objects, but functions are not allowed.

"use client"; export default function MyClientComponent({ name }) { return <p>Hello {name}</p>; }

Using the above client component from a server component:

import MyClientComponent from "./MyClientComponent"; export default function MyServerComponent() { return <MyClientComponent name="John" />; }

You can also wrap server components into client components. This is very useful when you want to use a server component inside a client component, like a React Context provider. The context will be available in all child client components. As the context is created only on the client, server components will not have access to the context.

"use client"; import { createContext } from "react"; const MyContext = createContext("unknown"); export default function MyProvider({ name, children }) { return <MyContext.Provider value={name}>{children}</MyContext.Provider>; }
import MyProvider from "./MyProvider"; export default async function MyServerComponent() { const name = await getUserName(); return ( <MyProvider name={name}> <p>Hello {name}</p> </MyProvider> ); }

Instead of creating a separate file for each client component, you can use the "use client" directive inside a function body. This allows you to define client components inline, right next to the server component that uses them.

import { useState } from "react"; function Counter() { "use client"; const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); } export default function App() { return ( <div> <h1>My App</h1> <Counter /> </div> ); }

The Counter function above will be automatically extracted into a separate client component module. The server component App will render a client reference to Counter instead of the function itself.

You can also use inline client components inside other functions. The framework will automatically detect any variables captured from the parent scope and pass them as props to the extracted client component.

import { useState } from "react"; export default function App() { const label = "clicks"; const Counter = () => { "use client"; const [count, setCount] = useState(0); return ( <div> <p>{label}: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; return ( <div> <h1>My App</h1> <Counter /> </div> ); }

In this example, the label variable is captured from App's scope and automatically forwarded as a prop to the client component. Module-level imports and top-level declarations used by the inline component are included in the extracted module directly.

Note: All captured variables must be serializable, just like regular client component props. Functions, class instances, and other non-serializable values cannot be captured.

You can define "use server" functions directly inside an inline "use client" component. This lets you keep the server logic and the client UI that calls it in a single file, without creating separate modules for either.

import { useState, useTransition } from "react"; export default function App() { function Counter() { "use client"; const [count, setCount] = useState(0); const [, startTransition] = useTransition(); async function increment(n) { "use server"; return n + 1; } return ( <div> <p>Count: {count}</p> <button onClick={() => startTransition(async () => { setCount(await increment(count)); }) } > Increment </button> </div> ); } return <Counter />; }

The framework extracts each directive into its own module automatically. The Counter component becomes a client module, and increment becomes a server function — no extra files needed.

You can define inline "use client" components inside a file that already has a top-level "use server" directive. This lets a server function define and return interactive client components without needing a separate file.

"use server"; import { useState } from "react"; export async function createBadge(label) { function Badge({ text }) { "use client"; const [clicked, setClicked] = useState(false); return ( <span onClick={() => setClicked(true)} style={{ cursor: "pointer" }}> {clicked ? `clicked:${text}` : text} </span> ); } return <Badge text={label} />; }

The file is treated as a server function module because of the top-level "use server" directive, but the Badge component is extracted into a separate client module. When createBadge is called, it renders the Badge with the given props and returns it through the RSC protocol. The client component is fully interactive after hydration — useState, event handlers, and other client-side features all work as expected.

You can make a component client-only by wrapping the component into a ClientOnly component. Children of the ClientOnly component will be rendered only on the client side.

import { ClientOnly } from "@lazarv/react-server/client"; export default function MyServerComponent() { return ( <div> <p>This is rendered on the server side</p> <ClientOnly> <p>This is rendered on the client side</p> <MyClientComponent /> </ClientOnly> </div> ); }