Shared components are the reusable building blocks — buttons, cards, form fields, layout primitives — used across many routes. This lesson covers how to design them so they work smoothly whether they're rendered from a Server or Client Component.
Most Shared Components Should Stay Server-Renderable
A purely presentational component — one that just accepts props and returns JSX, with no hooks or event handlers of its own — doesn't need "use client" at all. It can be safely imported and rendered from both Server and Client Components, since Next.js treats it as a Server Component by default and only ships it to the client bundle when it's actually used inside a Client Component tree.
Reserve "use client" specifically for shared components whose entire purpose is interactivity — buttons with onClick handlers, form inputs with local state, or anything using a browser-only API.
// components/Card.tsx — no directive, works everywhere
export default function Card({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) {
return (
<div className="card">
<h2>{title}</h2>
{children}
</div>
);
}
Card has no hooks or handlers, so it stays a Server Component when used from server-rendered pages, and becomes part of the client bundle only when a Client Component happens to render it.
Deciding Where a Shared Component Belongs
Does it use state, effects, or event handlers?
Yes → mark it "use client"
No → leave it as a Server Component (default)
Presentational components (cards, badges, typography wrappers) rarely need "use client".
Interactive components (buttons with handlers, toggles, form fields) almost always need it.
A shared component's own file determines its type — it doesn't inherit type from whoever imports it.
You can organize shared components in components/, regardless of type, since the directive controls behavior, not folder location.
Shared Components Cheat Sheet
Common component types and their typical classification.
Component
Typically
Card, Badge, Avatar
Server Component (presentational)
Button with onClick
Client Component
Modal, Dropdown (interactive)
Client Component
Icon (SVG wrapper)
Server Component
SearchInput (controlled input)
Client Component
Components That Work Both Ways
Some shared components, like a generic Container or Grid, are simple enough to remain Server Components while still being used inside Client Component trees — because the App Router only requires the specific file using hooks/handlers to be marked "use client", not every component it happens to render.
A Client Component can safely render a Server Component that's passed to it as children.
It cannot, however, directly import a Server Component's file and render it inline — only Server Components can do that.
Designing Props for Reusability
Reusable components should accept data and callbacks as props rather than reaching for global state or fetching their own data, which keeps them usable from both Server and Client contexts and easy to test in isolation.
Marking every component in components/ as "use client" by default, regardless of whether it needs it.
Having a shared component fetch its own data internally, making it hard to reuse in different rendering contexts.
Forgetting that a Client Component cannot directly import a Server Component's file, only receive one as children.
Duplicating similar components (e.g. two slightly different Card components) instead of adding a variant prop.
Key Takeaways
Most presentational shared components don't need "use client" and work in both Server and Client contexts.
Interactive shared components (buttons, inputs, toggles) typically do need the directive.
A component's type is determined by its own file, not by where it's imported.
Design shared components around props and callbacks rather than internal data fetching.
Client Components can receive Server Components as children, enabling flexible composition.
Pro Tip
When building a shared component library, default every new component to a plain Server Component and only add "use client" the moment TypeScript or Next.js actually complains about a hook or handler — this naturally minimizes your client-side JavaScript footprint over time.
You now know how to design reusable components. Next, learn component composition patterns for combining Server and Client Components effectively.