Layout Components
Layouts are components that wrap entire pages, providing consistent structure like headers, footers, and navigation.
Basic Layout¶
components/layout.jinja
{#def title #}
{#css layout.css #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ title }}</title>
{{ assets.render_css() }}
{{ assets.render_js() }}
</head>
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<main>
{{ content }}
</main>
<footer>
<p>© 2025 My Site</p>
</footer>
</body>
</html>
components/pages/home.jinja
{#import "../layout.jinja" as Layout #}
<Layout title="Home">
<h1>Welcome!</h1>
<p>This is the home page.</p>
</Layout>
Layout with Slots¶
Use named slots for customizable sections:
components/layout.jinja
{#def title #}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
{% slot head %}{% endslot %}
{{ assets.render_css() }}
</head>
<body>
<header>
{% slot header %}
<nav><a href="/">Home</a></nav>
{% endslot %}
</header>
<main>
{{ content }}
</main>
<footer>
{% slot footer %}
<p>© 2025</p>
{% endslot %}
</footer>
{% slot scripts %}{% endslot %}
{{ assets.render_js() }}
</body>
</html>
usage
{#import "layout.jinja" as Layout #}
<Layout title="Dashboard">
{% fill head %}
<meta name="robots" content="noindex">
{% endfill %}
{% fill header %}
<nav>
<a href="/dashboard">Dashboard</a>
<a href="/settings">Settings</a>
</nav>
{% endfill %}
<h1>Dashboard</h1>
<p>Welcome back!</p>
{% fill scripts %}
<script>console.log('Page loaded');</script>
{% endfill %}
</Layout>
Nested Layouts¶
Create specialized layouts that extend a base:
components/layouts/base.jinja
{#def title #}
{#css base.css #}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }} | My App</title>
{{ assets.render_css() }}
</head>
<body>
{{ content }}
{{ assets.render_js() }}
</body>
</html>
components/layouts/app.jinja
{#import "./base.jinja" as Base #}
{#import "../sidebar.jinja" as Sidebar #}
{#def title #}
{#css app.css #}
<Base title={{ title }}>
<div class="app-layout">
<Sidebar />
<main class="app-content">
{{ content }}
</main>
</div>
</Base>
components/layouts/auth.jinja
{#import "./base.jinja" as Base #}
{#def title #}
{#css auth.css #}
<Base title={{ title }}>
<div class="auth-layout">
<div class="auth-card">
{{ content }}
</div>
</div>
</Base>
usage
{#import "layouts/app.jinja" as App #}
<App title="Dashboard">
<h1>Dashboard</h1>
</App>
usage
{#import "layouts/auth.jinja" as Auth #}
<Auth title="Login">
<h1>Sign In</h1>
<form>...</form>
</Auth>
Layout with Navigation Highlighting¶
Pass the current page to highlight active nav items:
components/layout.jinja
{#def title, current_page="" #}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
{{ assets.render_css() }}
</head>
<body>
<nav>
<a href="/" class="{{ 'active' if current_page == 'home' else '' }}">Home</a>
<a href="/about" class="{{ 'active' if current_page == 'about' else '' }}">About</a>
<a href="/contact" class="{{ 'active' if current_page == 'contact' else '' }}">Contact</a>
</nav>
<main>{{ content }}</main>
{{ assets.render_js() }}
</body>
</html>
pages/about.jinja
{#import "layout.jinja" as Layout #}
<Layout title="About Us" current_page="about">
<h1>About Us</h1>
</Layout>
Conditional Layout Sections¶
components/layout.jinja
{#def title, show_sidebar=true, show_footer=true #}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
{{ assets.render_css() }}
</head>
<body>
<div class="layout {{ 'has-sidebar' if show_sidebar else '' }}">
{% if show_sidebar %}
<aside class="sidebar">
{% slot sidebar %}
<nav>Default sidebar</nav>
{% endslot %}
</aside>
{% endif %}
<main>{{ content }}</main>
</div>
{% if show_footer %}
<footer>
{% slot footer %}<p>© 2024</p>{% endslot %}
</footer>
{% endif %}
{{ assets.render_js() }}
</body>
</html>
usage
{# Full layout with sidebar #}
<Layout title="Dashboard">
{% fill sidebar %}
<nav>Custom sidebar</nav>
{% endfill %}
<h1>Dashboard</h1>
</Layout>
{# Minimal layout without sidebar #}
<Layout title="Login" show_sidebar={{ false }} show_footer={{ false }}>
<form>Login form</form>
</Layout>