Layouts Explained
Layouts are wrapper components that provide shared UI across multiple pages - like headers, footers, and navigation. They ensure consistency and reduce code duplication.
What is a Layout?
A layout wraps your page content with shared elements.
Without layout (repetitive):
// Every page repeats this:
function AboutPage() {
return (
<>
<Header />
<main>About content</main>
<Footer />
</>
)
}
function ContactPage() {
return (
<>
<Header />
<main>Contact content</main>
<Footer />
</>
)
}
With layout (DRY - Don't Repeat Yourself):
// Layout (once)
function DefaultLayout({ children }) {
return (
<>
<Header />
<main>{children}</main>
<Footer />
</>
)
}
// Pages (simple)
function AboutPage() {
return <DefaultLayout>About content</DefaultLayout>
}
function ContactPage() {
return <DefaultLayout>Contact content</DefaultLayout>
}
Our Layout System
We have several layouts for different page types:
components/layout/
├── DefaultLayout.tsx # Standard pages
├── ArticleLayout.tsx # Content-heavy pages
├── LandingLayout.tsx # Marketing/hero pages
└── GridLayout.tsx # Grid-based layouts
DefaultLayout
Used for: Most pages (contact, programs, etc.)
import Header from './Header'
import Footer from './Footer'
interface DefaultLayoutProps {
children: React.ReactNode
}
export default function DefaultLayout({ children }: DefaultLayoutProps) {
return (
<div className="min-h-screen flex flex-col">
<Header />
<main className="flex-1">
{children}
</main>
<Footer />
</div>
)
}
Features:
- Header at top
- Content in middle (flex-1 makes it grow)
- Footer at bottom
- Full height (min-h-screen)
Usage:
import DefaultLayout from '@/components/layout/DefaultLayout'
export default function ContactPage() {
return (
<DefaultLayout>
<h1>Contact Us</h1>
<ContactForm />
</DefaultLayout>
)
}
ArticleLayout
Used for: Content pages (about, model, etc.)
interface ArticleLayoutProps {
title: string
description?: string
children: React.ReactNode
}
export default function ArticleLayout({
title,
description,
children
}: ArticleLayoutProps) {
return (
<div className="min-h-screen flex flex-col">
<Header />
<main className="flex-1">
<div className="max-w-4xl mx-auto px-4 py-12">
<h1 className="text-4xl font-bold">{title}</h1>
{description && (
<p className="text-xl text-gray-600 mt-4">{description}</p>
)}
<div className="mt-8 prose">
{children}
</div>
</div>
</main>
<Footer />
</div>
)
}
Features:
- Takes title as prop
- Optional description
- Centered content (max-w-4xl)
- Typography styles (prose)
Usage:
import ArticleLayout from '@/components/layout/ArticleLayout'
export default function AboutPage() {
return (
<ArticleLayout
title="About K12worX"
description="Our mission and approach"
>
<p>Content goes here...</p>
</ArticleLayout>
)
}
LandingLayout
Used for: Homepage and landing pages
export default function LandingLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen">
<Header transparent />
{children}
<Footer />
</div>
)
}
Features:
- Transparent header (overlays content)
- No padding constraints
- Full creative freedom for hero sections
Usage:
import LandingLayout from '@/components/layout/LandingLayout'
export default function Home() {
return (
<LandingLayout>
<div className="hero bg-gradient-to-r from-blue-500 to-purple-600">
<h1>Big Hero Title</h1>
</div>
{/* More sections */}
</LandingLayout>
)
}
Root Layout (Special)
File: app/layout.tsx
This is the top-level layout that wraps the entire app:
import './globals.css'
import AccessGate from '@/components/AccessGate'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<AccessGate enabled={true} passcode="2025">
{children}
</AccessGate>
</body>
</html>
)
}
What it does:
- Wraps EVERYTHING
- Includes
<html>and<body>tags - Loads global CSS
- Applies access gate
- Every page goes through this!
You rarely edit this - it's configured once and left alone.
Layout Hierarchy
Layouts can nest:
RootLayout (app/layout.tsx)
└─ DefaultLayout (page's layout choice)
└─ Page content
Example:
// Root layout wraps everything
<html>
<body>
<AccessGate>
{/* DefaultLayout wraps this page */}
<div>
<Header />
<main>
{/* Your page content */}
<h1>Contact Us</h1>
</main>
<Footer />
</div>
</AccessGate>
</body>
</html>
When to Use Each Layout
| Layout | When to Use | Examples |
|---|---|---|
| DefaultLayout | Standard pages | Contact, Programs |
| ArticleLayout | Content-heavy pages | About, Model |
| LandingLayout | Marketing pages | Homepage |
| GridLayout | Grid-based content | Photo galleries |
Creating a Custom Layout
Need a special layout? Follow this pattern:
// components/layout/CustomLayout.tsx
import Header from './Header'
import Footer from './Footer'
interface CustomLayoutProps {
sidebar?: React.ReactNode
children: React.ReactNode
}
export default function CustomLayout({
sidebar,
children
}: CustomLayoutProps) {
return (
<div className="min-h-screen flex flex-col">
<Header />
<div className="flex-1 flex">
{sidebar && (
<aside className="w-64 bg-gray-100">
{sidebar}
</aside>
)}
<main className="flex-1">
{children}
</main>
</div>
<Footer />
</div>
)
}
Usage:
<CustomLayout sidebar={<MySidebar />}>
<h1>Page with sidebar</h1>
</CustomLayout>
Best Practices
1. Consistent Headers/Footers
Use the same Header and Footer components in all layouts:
// ✅ Good
<div>
<Header />
<main>{children}</main>
<Footer />
</div>
// ❌ Bad: Different header each time
<div>
<CustomHeader />
<main>{children}</main>
<DifferentFooter />
</div>
2. Props for Customization
Let pages customize the layout:
interface LayoutProps {
children: React.ReactNode
showSidebar?: boolean
headerTransparent?: boolean
}
export default function Layout({
children,
showSidebar = false,
headerTransparent = false
}: LayoutProps) {
return (
<div>
<Header transparent={headerTransparent} />
<div className="flex">
{showSidebar && <Sidebar />}
<main>{children}</main>
</div>
</div>
)
}
3. Keep Layouts Simple
Layouts should be wrappers, not complex pages:
// ✅ Good: Simple wrapper
function Layout({ children }) {
return (
<>
<Header />
<main>{children}</main>
<Footer />
</>
)
}
// ❌ Bad: Too much logic
function Layout({ children }) {
const data = await fetchData()
const processed = processData(data)
// 100 more lines...
return <div>...</div>
}
Common Patterns
Full-Height Layout
<div className="min-h-screen flex flex-col">
<Header />
<main className="flex-1">{children}</main>
<Footer />
</div>
Result: Footer always at bottom, even on short pages!
Centered Content
<main>
<div className="max-w-4xl mx-auto px-4">
{children}
</div>
</main>
Result: Content centered with max width.
Sidebar Layout
<div className="flex">
<aside className="w-64">{sidebar}</aside>
<main className="flex-1">{children}</main>
</div>
Result: Fixed sidebar, flexible main content.
Quick Reference
Using a layout:
import DefaultLayout from '@/components/layout/DefaultLayout'
export default function MyPage() {
return (
<DefaultLayout>
{/* Your content */}
</DefaultLayout>
)
}
Layout with props:
<ArticleLayout title="My Page" description="Description">
{/* Content */}
</ArticleLayout>
Our layouts:
DefaultLayout- Standard pagesArticleLayout- Content pagesLandingLayout- Hero/marketingGridLayout- Grid content
Summary
Layouts:
- Wrap pages with shared UI
- Provide consistency across the site
- Reduce code duplication
- Accept children prop for page content
Our system:
- Multiple layouts for different page types
- All layouts include Header and Footer
- Pages choose which layout to use
Best practice:
- Use existing layouts when possible
- Create custom layouts for special needs
- Keep layouts simple and focused
Section Complete!
You now understand:
- ✅ How the App Router works
- ✅ How pages create routes
- ✅ What components are and how to use them
- ✅ How layouts provide consistent structure
Next Up
Let's read actual code from the codebase:
Continue to Section 04: Reading Code →