<!-- Protocore Design System — ClientOnly -->
# ClientOnly

- **Category:** Utilities (`utilities`)
- **Slug:** `utilities/client-only`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { ClientOnly } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/utilities/client-only

> Defers its children until after the first client mount, so browser-only UI never runs during SSR.

## When to use it

Server-rendered React must produce the same markup on the server and on the first client render, or hydration warns and can visibly flicker. `ClientOnly` is the escape hatch for the genuinely client-only cases: a widget that reads `window.innerWidth`, a value derived from `Date.now()`, an iframe embed that a crawler shouldn't see.

Reach for it sparingly — most SSR mismatches are better fixed at the source (a stable key, a fixed locale, `suppressHydrationWarning` on a single leaf). Provide a `fallback` that reserves the right amount of space so the swap doesn't shift layout.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `children` | `ReactNode` | no | — | Rendered only after the component has mounted on the client. |
| `fallback` | `ReactNode` | no | `null` | Rendered on the server and during the first client paint. |

## Examples

### Deferring to the client

Wrap anything that depends on the browser — `window`, a non-deterministic value, a third-party embed — in `ClientOnly`. It renders `fallback` on the server and during the first paint, then swaps to `children` after mount, so hydration never mismatches.

```tsx
import { ClientOnly, Text, Spinner } from "@protocore/pds";

export default function ClientOnlyBasics() {
  return (
    <ClientOnly
      fallback={
        <Text size="sm" color="muted" as="span">
          <Spinner size="sm" /> Loading client value…
        </Text>
      }
    >
      <Text size="sm" mono>
        Rendered on the client — viewport width is{" "}
        {typeof window !== "undefined" ? window.innerWidth : 0}px.
      </Text>
    </ClientOnly>
  );
}
```

## Usage

**Do**

- Wrap only the subtree that truly needs the browser.
- Give a `fallback` that reserves the final layout size.
- Prefer it over sprinkling `typeof window` checks through render.

**Don't**

- Wrap the whole page; you lose SSR and SEO for everything.
- Use it to paper over a fixable hydration bug — fix the source.
- Expect its children in the server HTML; they render post-mount.

## Accessibility

**Notes**

- Renders no wrapper element, so it adds nothing to the accessibility tree.
- Because content appears after mount, ensure the `fallback` communicates loading state where the wait is perceptible.

## Related

`portal`, `relative-time`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
