Adding Page Overlay (Settings Page)
Route Shape
A page overlay is UI displayed on top of the main game screen (e.g. settings, save/load, gallery) without interrupting the game flow. By defining the route structure with Layout and Page, and navigating with useRouter, you can implement overlays like a settings page.
The example uses a settings overlay opened from the Quick Menu.
1. Define Layout and Page Structure
Define a settings layout with child pages such as general and audio. Player already creates the root layout, so place Page and Layout directly inside it. Page name={null} is the default page for its parent layout.
import { GameProviders, Layout, Page, Player } from "narraleaf-react";
function AppLayout() {
return (
<GameProviders>
<Player story={story} onReady={({ liveGame }) => liveGame.newGame()}>
{/* Default page (game stage) - path: / */}
<Page name={null}>
<GameStage />
</Page>
{/* Settings overlay - path: /settings, /settings/general, etc. */}
<Layout name="settings">
<Page name={null}>
<SettingsHome />
{/* /settings - settings entry or default tab */}
</Page>
<Page name="general">
<SettingsGeneral />
{/* /settings/general - general settings */}
</Page>
<Page name="audio">
<SettingsAudio />
{/* /settings/audio - audio settings */}
</Page>
</Layout>
</Player>
</GameProviders>
);
}Do not add RootLayout yourself. Nesting another root layout inside Player creates the wrong route boundary.
2. Implement the Settings Page Component
The settings page acts as an overlay with a semi-transparent backdrop and centered panel. Clicking the backdrop or a close button returns to the game.
import { useRouter } from "narraleaf-react";
function SettingsGeneral() {
const router = useRouter();
return (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
onClick={() => router.back()}
// Click overlay to close
>
<div
className="bg-gray-900 rounded-lg p-6 w-96 max-h-[80vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
// Prevent closing when clicking panel
>
<h2 className="text-xl font-bold mb-4">General Settings</h2>
{/* Settings form content */}
<button
className="mt-4 px-4 py-2 bg-amber-500 rounded"
onClick={() => router.back()}
>
Back
</button>
</div>
</div>
);
}3. Open Settings from Quick Menu
In the Quick Menu, call router.navigate("/settings") to open the settings overlay:
import { useRouter } from "narraleaf-react";
function QuickMenu() {
const router = useRouter();
const openSettings = () => router.navigate("/settings");
// Navigate to settings overlay
return (
<div className="fixed bottom-5 left-0 right-0 flex justify-center">
<button onClick={openSettings}>Settings</button>
</div>
);
}4. Router API Quick Reference
| Method | Description |
|---|---|
router.navigate(path) | Navigate to path, e.g. "/settings/general" |
router.back() | Go back |
router.forward() | Go forward |
router.clear().navigate(path) | Clear history then navigate (e.g. return to main) |
router.getCurrentPath() | Get current path |
router.replace(path) | Replace the current history entry |
router.canGoBack() | Check whether back() can navigate |
5. Add Enter/Exit Animations
Wrap page content with Motion's motion.div; LayoutRouter keeps the exiting page mounted until its animation finishes:
import { motion } from "motion/react";
function SettingsGeneral() {
const router = useRouter();
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
onClick={() => router.back()}
>
<motion.div
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.9, opacity: 0 }}
className="bg-gray-900 rounded-lg p-6 w-96"
onClick={(e) => e.stopPropagation()}
>
{/* ... */}
</motion.div>
</motion.div>
);
}See Also
- Layout - Layout component
- Page - Page component
- useRouter - Router hook
- Quick Menu - Quick menu implementation