Layout and Navigation
import { LayoutBase, NavBase, CardBase, GridBase } from "@lastshotlabs/snapshot/ui";
function AppShell({ children }) { return ( <LayoutBase variant="sidebar" nav={ <NavBase variant="sidebar" logo={{ text: "My App", path: "/" }} items={[ { label: "Dashboard", path: "/", icon: "home" }, { label: "Users", path: "/users", icon: "users" }, { label: "Settings", path: "/settings", icon: "settings" }, ]} collapsible /> } > {children} </LayoutBase> );}LayoutBase
Section titled “LayoutBase”Wraps your page content with nav, header, sidebar, main, and footer regions.
<LayoutBase variant="sidebar" nav={<NavBase ... />}> <h1>Page content</h1></LayoutBase>Variants:
| Variant | Description |
|---|---|
sidebar | Nav on the left, content on the right |
top-nav | Nav on top, content below |
stacked | Vertical stack: header, sidebar, main, footer |
minimal | Centered single column |
centered | Centered, max-width constrained |
full-width | No constraints, full viewport |
Layout slots for advanced composition:
<LayoutBase variant="sidebar" nav={<NavBase ... />} layoutSlots={{ header: <AnnouncementBar />, footer: <Footer />, }}> <Dashboard /></LayoutBase>NavBase
Section titled “NavBase”Main navigation component supporting sidebar and top-nav layouts.
Sidebar navigation
Section titled “Sidebar navigation”<NavBase variant="sidebar" logo={{ text: "My App", src: "/logo.svg", path: "/" }} items={[ { label: "Dashboard", path: "/", icon: "home" }, { label: "Users", path: "/users", icon: "users", badge: "12" }, { label: "Reports", path: "/reports", icon: "bar-chart", children: [ { label: "Revenue", path: "/reports/revenue" }, { label: "Growth", path: "/reports/growth" }, ]}, { label: "Settings", path: "/settings", icon: "settings" }, ]} collapsible pathname={currentPath} onNavigate={(path) => router.push(path)}/>Top navigation
Section titled “Top navigation”<NavBase variant="top-nav" logo={{ text: "My App", path: "/" }} items={[ { label: "Home", path: "/" }, { label: "Products", path: "/products" }, { label: "Pricing", path: "/pricing" }, ]}> <ButtonBase label="Sign in" variant="outline" /></NavBase>Nav item shape
Section titled “Nav item shape”| Prop | Type | Description |
|---|---|---|
label | string | Display text |
path | string | Navigation path |
icon | string | Icon name |
badge | string | Badge text |
disabled | boolean | Disable the item |
active | boolean | Force active state |
visible | boolean | Show/hide the item |
children | NavBaseItem[] | Nested sub-items |
NavLinkBase
Section titled “NavLinkBase”Individual nav link for custom navigation layouts.
import { NavLinkBase } from "@lastshotlabs/snapshot/ui";
<NavLinkBase path="/users" label="Users" icon="users" badge="12" active={pathname === "/users"} onNavigate={(path) => router.push(path)}/>NavUserMenuBase
Section titled “NavUserMenuBase”User dropdown menu with avatar for auth-aware navigation.
import { NavUserMenuBase } from "@lastshotlabs/snapshot/ui";
<NavUserMenuBase userName={user.name} userEmail={user.email} userAvatar={user.avatarUrl} showAvatar showName items={[ { label: "Profile", icon: "user", onClick: () => (window.location.href = "/profile") }, { label: "Settings", icon: "settings", onClick: () => (window.location.href = "/settings") }, { label: "Sign out", icon: "log-out", onClick: () => logout() }, ]}/>Grid layout
Section titled “Grid layout”GridBase
Section titled “GridBase”CSS Grid container.
import { GridBase } from "@lastshotlabs/snapshot/ui";
<GridBase columns={3} gap="md"> <CardBase title="Revenue">$48,200</CardBase> <CardBase title="Users">1,234</CardBase> <CardBase title="Orders">567</CardBase></GridBase>Responsive columns: Pass a string for responsive grid:
<GridBase columns="repeat(auto-fill, minmax(300px, 1fr))" gap="lg"> {items.map((item) => <CardBase key={item.id} title={item.name} />)}</GridBase>RowBase and ColumnBase
Section titled “RowBase and ColumnBase”Flexbox row and column containers.
import { RowBase, ColumnBase } from "@lastshotlabs/snapshot/ui";
<RowBase gap="md" align="center" justify="between"> <h1>Users</h1> <ButtonBase label="Add User" icon="plus" /></RowBase>
<ColumnBase gap="lg"> <SectionOne /> <SectionTwo /></ColumnBase>Cards and containers
Section titled “Cards and containers”CardBase
Section titled “CardBase”Styled card with optional title and subtitle.
<CardBase title="Project Details" subtitle="Last updated 2 hours ago" gap="md"> <p>Card content</p></CardBase>ContainerBase
Section titled “ContainerBase”Centered, max-width wrapper for page content.
import { ContainerBase } from "@lastshotlabs/snapshot/ui";
<ContainerBase maxWidth="lg" padding="xl"> <h1>Page Title</h1> <p>Content is centered and constrained.</p></ContainerBase>Max-width presets: xs, sm, md, lg, xl, 2xl, full, prose
BoxBase
Section titled “BoxBase”Generic element wrapper with customizable HTML tag.
import { BoxBase } from "@lastshotlabs/snapshot/ui";
<BoxBase as="section" className="hero-section"> <h1>Welcome</h1></BoxBase>HTML tags: div, section, article, aside, header, footer, main, nav, span
Spacing and sections
Section titled “Spacing and sections”SectionBase
Section titled “SectionBase”Full-width vertical section.
import { SectionBase } from "@lastshotlabs/snapshot/ui";
<SectionBase height="screen" align="center" justify="center"> <h1>Full-height hero</h1></SectionBase>SpacerBase
Section titled “SpacerBase”Empty spacing element.
import { SpacerBase } from "@lastshotlabs/snapshot/ui";
<ColumnBase> <Header /> <SpacerBase size="xl" /> <Content /></ColumnBase>Spacing tokens: 2xs, xs, sm, md, lg, xl, 2xl
Advanced layout
Section titled “Advanced layout”SplitPaneBase
Section titled “SplitPaneBase”Resizable two-pane split.
import { SplitPaneBase } from "@lastshotlabs/snapshot/ui";
<SplitPaneBase direction="horizontal" defaultSplit={30} minSize={200} first={<Sidebar />} second={<MainContent />}/>CollapsibleBase
Section titled “CollapsibleBase”Animated expand/collapse.
import { CollapsibleBase } from "@lastshotlabs/snapshot/ui";
<CollapsibleBase trigger={<ButtonBase label="Show details" variant="ghost" />} defaultOpen={false} duration="normal"> <p>Hidden content that expands on click.</p></CollapsibleBase>Mobile-responsive navigation
Section titled “Mobile-responsive navigation”For mobile, collapse the sidebar into a hamburger menu using DrawerBase:
import { DrawerBase, IconButtonBase, LayoutBase, NavBase, RowBase } from "@lastshotlabs/snapshot/ui";import { useState, useEffect } from "react";
const NAV_ITEMS = [ { label: "Dashboard", path: "/", icon: "home" }, { label: "Users", path: "/users", icon: "users" }, { label: "Settings", path: "/settings", icon: "settings" },];
function ResponsiveShell({ children }: { children: React.ReactNode }) { const [mobileOpen, setMobileOpen] = useState(false); const isMobile = useMediaQuery("(max-width: 768px)");
if (isMobile) { return ( <> <RowBase justify="between" align="center" style={{ padding: "0.75rem 1rem", borderBottom: "1px solid var(--sn-color-border)" }} > <IconButtonBase icon="menu" ariaLabel="Open menu" onClick={() => setMobileOpen(true)} /> <span style={{ fontWeight: 600 }}>My App</span> <span style={{ width: 40 }} /> </RowBase> <DrawerBase title="Navigation" side="left" size="sm" open={mobileOpen} onClose={() => setMobileOpen(false)} > <NavBase variant="sidebar" items={NAV_ITEMS} onNavigate={(path) => { window.location.href = path; setMobileOpen(false); }} /> </DrawerBase> <div style={{ padding: "1rem" }}>{children}</div> </> ); }
return ( <LayoutBase variant="sidebar" nav={<NavBase variant="sidebar" logo={{ text: "My App", path: "/" }} items={NAV_ITEMS} collapsible />} > {children} </LayoutBase> );}
// Simple media query hookfunction useMediaQuery(query: string) { const [matches, setMatches] = useState(() => typeof window !== "undefined" ? window.matchMedia(query).matches : false );
useEffect(() => { const mql = window.matchMedia(query); const handler = (e: MediaQueryListEvent) => setMatches(e.matches); mql.addEventListener("change", handler); return () => mql.removeEventListener("change", handler); }, [query]);
return matches;}On desktop, this renders the standard sidebar. On mobile, the sidebar becomes a drawer that slides in from the left when the hamburger icon is tapped.
Composition: full app shell
Section titled “Composition: full app shell”function App() { const { user } = snap.useUser(); const { mutate: logout } = snap.useLogout();
return ( <LayoutBase variant="sidebar" nav={ <NavBase variant="sidebar" logo={{ text: "Admin", src: "/logo.svg", path: "/" }} items={[ { label: "Dashboard", path: "/", icon: "home" }, { label: "Users", path: "/users", icon: "users" }, { label: "Reports", path: "/reports", icon: "bar-chart" }, ]} collapsible onNavigate={(path) => router.push(path)} /> } > <ContainerBase maxWidth="xl" padding="lg"> <RowBase justify="between" align="center"> <h1>Dashboard</h1> <NavUserMenuBase userName={user?.name} userAvatar={user?.avatarUrl} items={[ { label: "Settings", icon: "settings", onClick: () => (window.location.href = "/settings") }, { label: "Sign out", icon: "log-out", onClick: () => logout() }, ]} /> </RowBase> <SpacerBase size="lg" /> <GridBase columns={3} gap="md"> <StatCardBase label="Revenue" value="$48K" trend={{ direction: "up", value: "+12%" }} /> <StatCardBase label="Users" value="1,234" trend={{ direction: "up", value: "+5%" }} /> <StatCardBase label="Orders" value="567" trend={{ direction: "down", value: "-3%" }} /> </GridBase> </ContainerBase> </LayoutBase> );}All layout components
Section titled “All layout components”| Component | Description |
|---|---|
LayoutBase | App shell with 6 layout variants |
NavBase | Sidebar and top-nav navigation |
NavLinkBase | Individual nav link |
NavUserMenuBase | User dropdown menu |
GridBase | CSS Grid container |
RowBase | Flex row |
ColumnBase | Flex column |
CardBase | Styled card |
ContainerBase | Centered max-width wrapper |
BoxBase | Generic element wrapper |
SectionBase | Full-width section |
SpacerBase | Spacing element |
SplitPaneBase | Resizable split panes |
CollapsibleBase | Expand/collapse |
Next steps
Section titled “Next steps”- Data Tables and Lists — fill your layout with data
- Overlays and Modals — modals and drawers for CRUD
- Theming and Styling — customize layout appearance