Skip to content
react-cards-opening

Server rendering

Both packages render on a server. Nothing reads window during render, the reveal's overlay only mounts in the browser, and the plain functions (rollCards, chances, themeOf) run anywhere. This page is about the three things left to you: where the client boundary goes, where the stylesheet goes, and what a returning visitor sees first.

What is in the HTML

ComponentOn the server
CardHuntThe whole panel: headline, button, grid, badges. Readable with JavaScript off.
ScanGridThe grid, veiled or not.
CardThe card, face up or down.
CardOpeningNothing. The overlay is a portal that mounts after hydration.

Next.js

app/layout.tsx
import "@react-cards-opening/ui/styles.css";
app/hunt.tsx
"use client";

import { useOpenedCards } from "@react-cards-opening/core";
import { CardHunt } from "@react-cards-opening/ui";

export function Hunt({ cards, levels }) {
  const { opened, open } = useOpenedCards("deal");
  return <CardHunt cards={cards} opened={opened} onOpen={open} levels={levels} />;
}

The file that uses the hooks is a client component: the packages do not mark themselves with use client, so that functions like rollCards stay callable from server code. The cards and the grid can come from a server component above it as props: they are plain data.

Returning visitors

The server does not know what is in local storage, so its HTML shows every card unopened. useOpenedCards reads storage before the first paint, which is soon enough for most pages. If the two states look very different, hold the piece back until ready:

tsx
const { opened, open, ready } = useOpenedCards("deal");
if (!ready) return <div style={{ minHeight: 360 }} />;

Or keep opened cards on the server and render the right state the first time. See Keep opened cards.

Random things

Anything random that is rendered has to be the same on both sides. Deal with a seed in rollCards, and build the grid from data, not from Math.random(). Where a card hides is random on purpose, and it is picked in the browser when the scan starts, so it never reaches the HTML.

Last updated . Read this page as Markdown.