Skip to content
Twilight React Playground
ثيم رائدaren

useIsClient

hookBeginnerserverbrowserlive demo

Returns false while the page is rendered on the server and during hydration, then true once the component has mounted in the browser.

import { useIsClient } from '@salla.sa/twilight-theme-engine/hooks';

In plain words

A storefront page is built twice. First the server runs your components and sends finished HTML (server-side rendering, SSR). Then the browser runs the same components again and attaches itself to that HTML (hydration). Both runs must produce the same result.

Things like the window size, localStorage or the Salla SDK exist only in the browser. useIsClient() is false in both of those first runs and becomes true right after, so you can show browser-only values without the two runs disagreeing.

Signature

function useIsClient(): boolean

Try it live

The first render shows "…", because the server has no window. After the component mounts in the browser the hook flips to true.Try this: reload the page and watch the values: the dots come first, then the real width and language.
Storefront canvas · ar · RTL

isClient: false

Window width:

Browser language:

What a theme writes
import { useIsClient } from '@salla.sa/twilight-theme-engine/hooks';

export function WindowWidth() {
  const isClient = useIsClient();
  // Never branch on `typeof window` in render: the server and the first browser render must match.
  return <span>{isClient ? window.innerWidth : '…'}</span>;
}

Example

app/components/RecentlyViewed.tsx
import { useIsClient } from '@salla.sa/twilight-theme-engine/hooks';

export function RecentlyViewed() {
  const isClient = useIsClient();
  if (!isClient) return null; // the server has no localStorage

  const ids = JSON.parse(localStorage.getItem('recently-viewed') ?? '[]') as number[];
  return <p>You viewed {ids.length} products recently.</p>;
}

How it behaves

  • It is useState(false) plus an effect that sets true, so every component that calls it renders one extra time after mounting.

  • HookSlot uses it to add the <salla-hook> element only after hydration.

  • It has no subpath of its own: import it from @salla.sa/twilight-theme-engine/hooks.

Gotchas

  • Branching on typeof window !== 'undefined' inside render gives the server and the first browser render different output, and React reports a hydration mismatch. Use useIsClient() (or an effect) instead.

  • Content behind isClient is missing from the server HTML, so search engines and the first paint do not see it, and the layout can shift when it appears. Reserve its space or keep essential content server-rendered.

Related

Source and docs