BESPA gives you three ways to render one page inside another. They share the same mechanism — EmbedHandler invokes a handler against an in-memory response recorder, slices the resulting <body>, and drops it into a container widget. What differs is the container and the state contract around it.
Use this page to pick the right one. Each row links to its deep-dive.
| Mechanism | Container | Controlled by | Visually | Reach for it when |
|---|---|---|---|---|
| Inline embed | GroupingFrame, any container |
A boolean-ish state key (HideIfEmpty) |
Part of document flow | A sub-page belongs in-line — a detail strip, a settings block under a header |
| Modal | Modal("key") |
One state key holding the embedded path | Centered overlay, dims background | A focused interaction that should pause the rest of the page |
| Side panel | SidePanel("key") |
One state key holding the embedded path | Sliding pane, doesn’t dim | A contextual surface the user reads beside the main content |
| Named frame | GroupingFrame(...).WithName("x") |
Links that set WithTarget("x") |
Multiple independent surfaces on one screen | A dashboard, IDE-style split, or chat-and-thread layout — each pane navigates on its own |
All four are the same shape under the hood:
container.Add(wf.EmbedHandler(handler, r, "GET", path, nil))
What changes is the container widget and how path is decided:
path is fixed in code (or computed once). The container shows or hides based on a state predicate.path is read from a state variable. Empty state means the overlay isn’t rendered. Setting the state to a path opens it; clearing the state closes it.path is fixed at first paint, but the frame is given a name via WithName. Subsequent links elsewhere on the page can swap the frame’s content by targeting that name.Whichever mechanism you pick, the embedded page sees an isolated slice of state. A variable named x in the embed doesn’t collide with one of the same name in the parent. That’s what lets you compose pages without coordinating their state vocabularies.
A useful disambiguation when you’re reading example code:
wf.Modal("...") or wf.SidePanel("...") at the top of the page → overlay. State key in the constructor.wf.GroupingFrame(...).WithName("...") → named frame. Look for links with WithTarget("...") matching that name.wf.GroupingFrame(...) without WithName, holding an EmbedHandler → inline embed. Usually paired with HideIfEmpty or a similar predicate.Modal state key and a frame name. They live in different namespaces but a reader of your code won’t know that._back. Overlays install ?_back=^?modal= (or similar) so the embedded page can dismiss itself. Inline embeds and named frames usually don’t — the dismiss model is different._back plumbing explained._top / _parent / _blank / custom-name target keywords.^ and ~ prefixes that overlays and frames lean on.