Navigation state
Navigation state
Clicking a row should open that record — without your app doing any routing. Bolt owns record navigation: the selected record stack is serialized in the URL, and the shell renders the registered detail surface for it. This guide describes that contract.
What people see
The Bolt shell renders a sidebar and a main app surface. Platform and Applications are uppercase muted section labels in the sidebar — host plugins and tenant apps remain visually distinct. They are not navigation items themselves.
Opening a record does not navigate to a new document route. The app stays on /app/{appName} ; the selected record stack lives in ?stack= and the shell renders a detail sheet when viewMode === 'sidesheet' .
┌─ TenantWorkspaceShell ─────────────────────────────────────┐
│ [Sidebar] │ Main app surface │
│ PLATFORM — host plugins │ CollectionTable / … │
│ APPLICATIONS — tenant apps │ │ click row │
│ │ ▼ │
│ │ pushes ?stack= in URL │
└─────────────────────────────────┴─────────────────────────┘
│
viewMode=sidesheet ▼
┌──────────────────────────────────────┐
│ Right sheet (one per stack frame) │
│ Record detail + breadcrumbs │
└──────────────────────────────────────┘ The stack contract
Navigation state is a single selected record stack serialized in ?stack= :
type NavState = {
stack: NavStackItem[];
};
type NavStackItem = {
collection_name: string;
record_id: string;
node_id: string; // which surface the row was opened from (highlighting only)
viewMode: 'page' | 'sidesheet';
}; A frame names a collection_name and a record_id , and the shell renders that record with its authored representation. Nothing is registered and nothing has to be on screen first: CollectionTable and CollectionKanban open a record by merging a frame into the URL stack, so a pasted link resolves exactly as a click does.
Route context
Lightweight route context only identifies where the URL belongs: organization and an optional appName . It does not decide rendering behavior. When switching apps or clearing selection, the shell uses that context to preserve or reset ?stack= while staying on the current app URL.
Forms in detail surfaces
Create, display, and edit in table, kanban, and detail views share one compiler-owned collection role: +representation.svelte . Collection surfaces resolve it from the generated static map and pass record={null} for create or the existing row for display/edit — call sites do not register or override record components. See UI components.
Related guides
- Apps — tenant application entry components the shell loads
- Collections — models that table and kanban surfaces navigate into
- UI components — inline forms in table, kanban, and detail