use Scrim

Reads a store's status and readiness, and re-renders when they change.

Usage

The config moves the nodes. When a component has to react to the scrim, it reads the store with useScrim.

tsx
const { status, isReady } = useScrim(scrimRouteConfig);

isReady

The title in this site's scrim uses a custom font, so I show it only once until has waited for the fonts.

tsx
// features/scrim/scrim_route.tsx
export const ScrimRoute = () => {
  const { isReady } = useScrim(scrimRouteConfig);

  return (
    <div ref={scrimRouteConfig.node(SCRIM_NODE_CURTAIN)} aria-hidden className="fixed inset-0 z-9999 bg-main">
      <h1 className={cn("font-secondary transition-opacity duration-300", !isReady && "opacity-0")}>{title}</h1>
    </div>
  );
};

status

status reports the ends too: covered once the scrim has covered, and idle once it has left. Here a hero animates in with Motion when the scrim is gone.

tsx
export const Hero = () => {
  const { status } = useScrim(scrimRouteConfig);

  return (
    <motion.h1 initial={{ opacity: 0 }} animate={{ opacity: status === "idle" ? 1 : 0 }}>
      {title}
    </motion.h1>
  );
};

And here the page scrolls back to the top while nobody can see it.

tsx
const { status } = useScrim(scrimRouteConfig);

useEffect(() => {
  if (status === "covered") window.scrollTo(0, 0);
}, [status]);

On the server

On the server the store never moves: status is initial and isReady is false. Hydration reads the same values, then the component follows the store.

Reference

Returns

proptypedefault
status"idle" | "entering" | "covered" | "leaving"—where the scrim is
isReadyboolean—true once until has resolved