Rendering a shell

How a product renders its shell document with PolyxdFrame, puts screens in the Outlet, routes navigation actions, and supplies its own components through Custom.

A shell document is the product's frame: the app bar, the main navigation, an aside, a footer, and an Outlet where every screen renders. It has surface.kind: "shell", a Frame at the root, and is always authored (see Generated or authored). @polyxd/react renders it with PolyxdFrame.

import { PolyxdFrame } from "@polyxd/react";
import shell from "./authored/shell.json";

<PolyxdFrame
  document={shell.document}
  data={shellData}                 // what the shell binds to: the person, badges, the current item
  theme="material3"
  mode={mode}
  current={{ key: route.key, title: route.title }}   // marks the navigation item; the AppBar shows the title on phones
  components={{ "halden.fab": Fab }}                  // host components a Custom names
  onAction={(e) => {
    if (e.name === "nav.go") navigate(e.context.to as string);
    if (e.name === "ask.open") openAsk();
  }}
>
  <Routes>…</Routes>               {/* whatever the product shows: PolyxdSurface documents, React screens, both */}
</PolyxdFrame>

What the frame does#

useFrame() gives a host's own screens the layout the frame chose ({ navigation: "side" | "rail" | "bar" | "drawer", compact }), so a React screen can, say, leave room for the bottom bar.

Data#

A shell is long-lived, so unlike a surface it adopts each new data object the host passes: a badge count changes, the frame follows. Keep shellData derived from the product's store.

Verification#

A shell is verified like any document: polyxd-verify authored/shell.json renders it in every pack with a stand-in screen in the Outlet and audits landmarks, target sizes, contrast and the shell rules. The demos' pipeline treats authored/shell.json like every other authored document.

What stays in code#

Screens can be documents or React; the frame can be a document or React; the two mix freely. What has no document form is behaviour that isn't a component: routing, data fetching, animation beyond the packs' motion tokens, and anything a Custom names. Halden's shell is a document with one Custom (the floating ask button); Foundry's and Wexley's frames are still React on the same tokens, and look the same.

Polyxd is an early preview. Found something unclear? It will get better with your feedback.