He
HeliumTS
Note:

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.tsx
2export 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.tsx
2export 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}
10
11// src/pages/(marketing)/_layout.tsx
12export 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}
20
21// src/pages/(auth)/_layout.tsx
22export 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 # MarketingLayout
4│ ├── index.tsx → / (wrapped by MarketingLayout)
5│ └── about.tsx → /about (wrapped by MarketingLayout)
6├── (app)/
7│ ├── _layout.tsx # AppLayout
8│ └── dashboard.tsx → /dashboard (wrapped by AppLayout)
9└── (auth)/
10 ├── _layout.tsx # AuthLayout
11 ├── 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 pages
3├── (app)/
4│ ├── _layout.tsx # AppLayout - wraps (app) pages
5│ ├── dashboard.tsx # [RootLayout → AppLayout]
6│ └── settings/
7│ ├── _layout.tsx # SettingsLayout - wraps settings pages
8│ ├── 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.tsx
2import { Link, useRouter } from "heliumts/client";
3
4export default function SettingsLayout({ children }: { children: React.ReactNode }) {
5 const router = useRouter();
6
7 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 ];
13
14 return (
15 <div className="settings-layout">
16 <h1>Settings</h1>
17 <nav className="tabs">
18 {tabs.map((tab) => (
19 <Link
20 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";
2
3export default function Layout({ children }: LayoutProps) {
4 return (
5 <div className="layout">
6 {children}
7 </div>
8 );
9}
10
11// Or with explicit typing
12interface LayoutProps {
13 children: React.ReactNode;
14}
15
16export default function Layout({ children }: LayoutProps) {
17 return <div>{children}</div>;
18}

Layout Best Practices

  1. Keep layouts focused: Each layout should handle one level of UI structure
  2. Use route groups: Organize pages by feature or domain with group layouts
  3. Avoid heavy computations: Layouts persist across navigations, so expensive operations will run on every page
  4. Use PageTransition in root layout: Apply transitions at the highest level for consistent behavior
  5. Don't duplicate layout logic: If multiple groups need the same layout, consider a shared component