HeliumTS is under pre-beta and active development. Expect bugs and breaking changes. If you find any issues, please report them in our GitHub
A stable release is planned for early December 2025.
Layouts
Overview
Layouts allow you to share UI between pages. They wrap page components and can be nested to create complex page structures with shared headers, sidebars, and footers.
Key Features:
- Nested layouts: Layouts can wrap other layouts
- Route group layouts: Apply layouts to specific groups of pages
- Preserved state: Layout components don't remount on navigation
- Automatic wrapping: Pages are automatically wrapped by their parent layouts
Root Layout
Create _layout.tsx at the root of src/pages to wrap all pages:
1// src/pages/_layout.tsx2export default function RootLayout({ children }: { children: React.ReactNode }) {3 return (4 <div>5 <header>Global Header</header>6 <main>{children}</main>7 <footer>Global Footer</footer>8 </div>9 );10}
This layout wraps every page in your application, making it ideal for:
- Global navigation headers
- Site-wide footers
- Theme providers
- Analytics scripts
- Error boundaries
Group Layouts
Create _layout.tsx inside route groups to wrap only pages in that group:
1// src/pages/(app)/_layout.tsx2export default function AppLayout({ children }: { children: React.ReactNode }) {3 return (4 <div className="app-layout">5 <nav>App Navigation</nav>6 <div className="content">{children}</div>7 </div>8 );9}1011// src/pages/(marketing)/_layout.tsx12export default function MarketingLayout({ children }: { children: React.ReactNode }) {13 return (14 <div className="marketing-layout">15 <header>Marketing Header</header>16 <main>{children}</main>17 </div>18 );19}2021// src/pages/(auth)/_layout.tsx22export default function AuthLayout({ children }: { children: React.ReactNode }) {23 return (24 <div className="auth-layout min-h-screen flex items-center justify-center">25 <div className="auth-card">{children}</div>26 </div>27 );28}
Each route group can have its own distinct layout:
1src/pages/2├── (marketing)/3│ ├── _layout.tsx # MarketingLayout4│ ├── index.tsx → / (wrapped by MarketingLayout)5│ └── about.tsx → /about (wrapped by MarketingLayout)6├── (app)/7│ ├── _layout.tsx # AppLayout8│ └── dashboard.tsx → /dashboard (wrapped by AppLayout)9└── (auth)/10 ├── _layout.tsx # AuthLayout11 ├── login.tsx → /login (wrapped by AuthLayout)12 └── register.tsx → /register (wrapped by AuthLayout)
Nested Layouts
Layouts can be nested in subdirectories for more complex UI structures:
1src/pages/2├── _layout.tsx # RootLayout - wraps ALL pages3├── (app)/4│ ├── _layout.tsx # AppLayout - wraps (app) pages5│ ├── dashboard.tsx # [RootLayout → AppLayout]6│ └── settings/7│ ├── _layout.tsx # SettingsLayout - wraps settings pages8│ ├── index.tsx # [RootLayout → AppLayout → SettingsLayout]9│ └── profile.tsx # [RootLayout → AppLayout → SettingsLayout]
Rendering Order
Layouts render from outer to inner (Root → Group → Nested):
1<RootLayout>2 <AppLayout>3 <SettingsLayout>4 <ProfilePage />5 </SettingsLayout>6 </AppLayout>7</RootLayout>
Settings Layout Example
1// src/pages/(app)/settings/_layout.tsx2import { Link, useRouter } from "heliumts/client";34export default function SettingsLayout({ children }: { children: React.ReactNode }) {5 const router = useRouter();67 const tabs = [8 { href: "/settings", label: "General" },9 { href: "/settings/profile", label: "Profile" },10 { href: "/settings/security", label: "Security" },11 { href: "/settings/notifications", label: "Notifications" },12 ];1314 return (15 <div className="settings-layout">16 <h1>Settings</h1>17 <nav className="tabs">18 {tabs.map((tab) => (19 <Link20 key={tab.href}21 href={tab.href}22 className={router.path === tab.href ? "active" : ""}23 >24 {tab.label}25 </Link>26 ))}27 </nav>28 <div className="settings-content">{children}</div>29 </div>30 );31}
Layout Props
Layouts receive a children prop containing the page content:
1import type { LayoutProps } from "heliumts/client";23export default function Layout({ children }: LayoutProps) {4 return (5 <div className="layout">6 {children}7 </div>8 );9}1011// Or with explicit typing12interface LayoutProps {13 children: React.ReactNode;14}1516export default function Layout({ children }: LayoutProps) {17 return <div>{children}</div>;18}
Layout Best Practices
- Keep layouts focused: Each layout should handle one level of UI structure
- Use route groups: Organize pages by feature or domain with group layouts
- Avoid heavy computations: Layouts persist across navigations, so expensive operations will run on every page
- Use PageTransition in root layout: Apply transitions at the highest level for consistent behavior
- Don't duplicate layout logic: If multiple groups need the same layout, consider a shared component