Server first
Most components render on the server and add no JavaScript. Here is which ones, and why.
The three kinds
Every component is one of three kinds. The kind is shown on the chip beside its name.
Of the 52 component imports today: 19 server, 13 split and 20 client, read from each component's meta.ts.
What may cross the boundary
Only what React can serialise: strings, numbers, booleans, plain objects, arrays and children. A function never crosses, except a Server Action.
// app/page.tsx - a Server Component
<Command items={commands} getKey={(c) => c.id} getLabel={(c) => c.label} onSelect={run} />
// getKey, getLabel and onSelect are functions: they cannot cross'use client'
// the file that configures a palette is a client file
import { Command } from 'topclassui/command'
export function Search({ commands }: { commands: { id: string, label: string }[] }) {
return (
<Command
items={commands}
getKey={(command) => command.id}
getLabel={(command) => command.label}
onSelect={(command) => { window.location.assign(`/docs/${command.id}`) }}
/>
)
}Why index.tsx has no hooks
Markup lives in index.tsx, behaviour in hook.ts. index.tsx never contains 'use client' and never imports hook.ts. A build check enforces it.
// index.tsx - server
import { useId } from 'react' // allowed
import { use } from 'react' // allowed
// anything else fails check-boundaries:
// useState, useEffect, useRef, useMemo, useCallbackThe two hooks a Server Component is allowed to call.
How a split component works
The server half renders the markup and resolves anything needing the server, such as icon names. The client half adds the one behaviour.
// tag/index.tsx - server
export function Tag({ onRemove, children, ...rest }: TagProps) {
if (onRemove) {
return <Removable onRemove={onRemove} {...rest}>{children}</Removable> // the x is a client part
}
return <span {...rest}>{children}</span> // still server
}How sizes are checked
Every component has a size budget. The check that fails the build when a budget is crossed is not built yet.
What it costs you
Server-first comes with constraints. These are the ones you will notice.
No onClick on a server component
A command palette needs a client file
getKey, getLabel and onSelect are functions, so Command must be configured in a file marked 'use client'. Select and Combobox take plain data and render from a server file.