Nested Overlays
A drawer, a sheet, and search stacked three deep — Escape closes only the top layer, and the page never scrolls behind them.
Sidebar → BottomSheet → SearchModaloverlay-stacksidebarbottom-sheetsearch-modal9:41
In this demo
Ridgeline — trail maps
What to try
- Open the trail list, pick a trail, then search from its sheet
- Press Escape three times — one layer closes each time
Code
app.tsx
import { AppShell, Sidebar, BottomSheet, SearchModal } from "appshell-react";
import { useState } from "react";
export default function App() {
const [sidebarOpen, setSidebarOpen] = useState(false);
const [sheetOpen, setSheetOpen] = useState(false);
const [searchOpen, setSearchOpen] = useState(false);
// Nesting guarantees the open order: Sidebar, then Sheet, then Search.
// The overlay stack handles the rest — Escape (or Android back) always
// closes just the topmost layer, and the page stays scroll-locked until
// the last one closes.
return (
<AppShell safeArea>
<div className="fixed inset-0">{/* map canvas */}</div>
<Sidebar open={sidebarOpen} onClose={() => setSidebarOpen(false)} aria-label="Saved trails">
<button onClick={() => setSheetOpen(true)}>Widowmaker Ridge</button>
</Sidebar>
<BottomSheet open={sheetOpen} onClose={() => setSheetOpen(false)} aria-label="Trail details">
<button onClick={() => setSearchOpen(true)}>Search other trails</button>
</BottomSheet>
<SearchModal open={searchOpen} onClose={() => setSearchOpen(false)} aria-label="Search trails">
{(q) => <TrailResults query={q} />}
</SearchModal>
</AppShell>
);
}