> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Layouts

> Create consistent page structures with layouts

Layouts are the HTML shell that wraps your pages. They contain the common structure shared across pages: doctype, head, navigation, footer, and more.

## What is a Layout?

A layout is a template that defines the outer structure of your pages. Instead of repeating the HTML boilerplate in every page, you define it once in a layout.

**Without layouts - every page repeats this:**

```html theme={null}
<!DOCTYPE html>
<html>
<head>
    <title>Page Title</title>
    <link rel="stylesheet" href="/styles.css">
</head>
<body>
    <nav>...</nav>
    <!-- Page content here -->
    <footer>...</footer>
</body>
</html>
```

**With layouts - define once, pages fill in the content:**

```html theme={null}
<!DOCTYPE html>
<html>
<head>
    <title>{{.Data.Title}}</title>
    <link rel="stylesheet" href="/styles.css">
</head>
<body>
    <nav>...</nav>
    {{.Content}}
    <footer>...</footer>
</body>
</html>
```

## Directory Structure

Layouts live in the `layouts/` subdirectory:

```
views/
├── layouts/
│   ├── default.html    # Default layout
│   ├── admin.html      # Admin layout
│   └── minimal.html    # Minimal layout
└── pages/
    ├── home.html
    └── dashboard.html
```

## Creating a Layout

### Basic Layout

```html theme={null}
<!-- views/layouts/default.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{.Data.Title}}</title>
    <link rel="stylesheet" href="/css/main.css">
</head>
<body>
    <header>
        <nav>
            <a href="/">Home</a>
            <a href="/about">About</a>
            <a href="/contact">Contact</a>
        </nav>
    </header>

    <main>
        {{.Content}}
    </main>

    <footer>
        <p>&copy; 2024 My Company</p>
    </footer>

    <script src="/js/main.js"></script>
</body>
</html>
```

**Key point:** `{{.Content}}` is where the rendered page content is inserted.

### Page Template

Pages simply provide content - no layout wrapper needed:

```html theme={null}
<!-- views/pages/home.html -->
<h1>Welcome, {{.Data.Name}}!</h1>
<p>This is the home page.</p>
```

## How It Works

When you render a page:

```go theme={null}
view.Render(c, "home", view.Data{
    "Title": "Home",
    "Name":  "Alice",
})
```

The engine:

1. Renders `pages/home.html` with your data
2. Puts the result in `.Content`
3. Renders `layouts/default.html` with `.Content` set

## Setting the Default Layout

Configure the default layout in your engine:

```go theme={null}
engine := view.New(view.Config{
    Dir:           "./views",
    DefaultLayout: "default",  // Uses layouts/default.html
})
```

## Multiple Layouts

Create different layouts for different sections of your site.

### Admin Layout

```html theme={null}
<!-- views/layouts/admin.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Admin - {{.Data.Title}}</title>
    <link rel="stylesheet" href="/css/admin.css">
</head>
<body class="admin">
    <div class="admin-sidebar">
        <nav>
            <a href="/admin">Dashboard</a>
            <a href="/admin/users">Users</a>
            <a href="/admin/posts">Posts</a>
            <a href="/admin/settings">Settings</a>
        </nav>
    </div>
    <div class="admin-content">
        <header>
            <h1>{{.Data.PageTitle}}</h1>
        </header>
        <main>
            {{.Content}}
        </main>
    </div>
</body>
</html>
```

### Using a Different Layout

Override the default layout when rendering:

```go theme={null}
func dashboardHandler(c *mizu.Ctx) error {
    return view.Render(c, "admin/dashboard", view.Data{
        "Title":     "Dashboard",
        "PageTitle": "Admin Dashboard",
        "Stats":     stats,
    }, view.Layout("admin"))
}
```

### Minimal Layout

For simple pages that don't need full navigation:

```html theme={null}
<!-- views/layouts/minimal.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{{.Data.Title}}</title>
    <style>
        body {
            font-family: sans-serif;
            max-width: 600px;
            margin: 50px auto;
            padding: 20px;
        }
    </style>
</head>
<body>
    {{.Content}}
</body>
</html>
```

```go theme={null}
func loginHandler(c *mizu.Ctx) error {
    return view.Render(c, "login", view.Data{
        "Title": "Login",
    }, view.Layout("minimal"))
}
```

## No Layout

For AJAX responses, partial HTML, or API endpoints that return HTML fragments:

```go theme={null}
// Returns just the page content, no layout
view.Render(c, "user-row", data, view.NoLayout())
```

This is useful for:

* HTMX partial updates
* AJAX content loading
* Email templates (that define their own complete HTML)

## Layout Data Access

Layouts have access to all the same data as pages:

| Field          | Description                |
| -------------- | -------------------------- |
| `.Data`        | Your data from the handler |
| `.Page.Name`   | Page template name         |
| `.Page.Layout` | Layout name                |
| `.Content`     | Rendered page content      |

```go theme={null}
view.Render(c, "home", view.Data{
    "Title":       "Home Page",
    "CurrentUser": user,
    "Year":        time.Now().Year(),
})
```

```html theme={null}
<!-- views/layouts/default.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{{.Data.Title}}</title>
</head>
<body>
    <nav>
        {{if .Data.CurrentUser}}
            <span>Hello, {{.Data.CurrentUser.Name}}</span>
            <a href="/logout">Logout</a>
        {{else}}
            <a href="/login">Login</a>
        {{end}}
    </nav>

    <main>
        {{.Content}}
    </main>

    <footer>
        <p>&copy; {{.Data.Year}} My Company</p>
    </footer>
</body>
</html>
```

## Common Patterns

### Dynamic Navigation

Highlight the current page:

```html theme={null}
<!-- views/layouts/default.html -->
<nav>
    <a href="/" class="{{if eq .Page.Name "home"}}active{{end}}">Home</a>
    <a href="/about" class="{{if eq .Page.Name "about"}}active{{end}}">About</a>
    <a href="/contact" class="{{if eq .Page.Name "contact"}}active{{end}}">Contact</a>
</nav>
```

Or pass the current path:

```go theme={null}
view.Data{
    "CurrentPath": c.Path(),
}
```

```html theme={null}
<a href="/" class="{{if eq .Data.CurrentPath "/"}}active{{end}}">Home</a>
```

### Flash Messages

Display flash messages from sessions:

```html theme={null}
{{if .Data.Flash}}
<div class="flash flash-{{.Data.Flash.Type}}">
    {{.Data.Flash.Message}}
</div>
{{end}}
```

### Page-Specific Body Classes

```html theme={null}
<body class="{{.Data.BodyClass}}">
```

```go theme={null}
view.Data{
    "BodyClass": "page-home dark-mode",
}
```

### Meta Tags

```html theme={null}
<head>
    <title>{{.Data.Title}}</title>
    <meta name="description" content="{{.Data.Description}}">
    {{if .Data.NoIndex}}<meta name="robots" content="noindex">{{end}}
</head>
```

### Conditional Scripts

```html theme={null}
<body>
    {{.Content}}

    <script src="/js/main.js"></script>
    {{if .Data.NeedsChart}}
    <script src="/js/chart.js"></script>
    {{end}}
</body>
```

## Best Practices

### 1. Keep Layouts Focused

Each layout should serve a clear purpose:

* `default.html` - Main public pages
* `admin.html` - Admin panel
* `auth.html` - Login/signup pages
* `email.html` - Email templates

### 2. Pass Common Data via Middleware

Instead of passing the same data in every handler, use middleware:

```go theme={null}
func commonDataMiddleware(next mizu.Handler) mizu.Handler {
    return func(c *mizu.Ctx) error {
        c.Locals("Year", time.Now().Year())
        c.Locals("CurrentPath", c.Path())
        return next(c)
    }
}
```

### 3. Use Meaningful Names

```go theme={null}
// Good: clear purpose
view.Layout("admin")
view.Layout("email")

// Avoid: unclear
view.Layout("layout2")
view.Layout("other")
```

### 4. Don't Overcomplicate

Start simple. Most sites only need 2-3 layouts:

* Main layout for public pages
* Admin layout for backend
* Minimal layout for auth pages

### 5. Test All Layouts

Make sure every layout works with your data:

```go theme={null}
func TestLayouts(t *testing.T) {
    engine := view.New(config)

    layouts := []string{"default", "admin", "minimal"}
    for _, layout := range layouts {
        var buf bytes.Buffer
        err := engine.Render(&buf, "test-page", testData, view.Layout(layout))
        if err != nil {
            t.Errorf("Layout %s failed: %v", layout, err)
        }
    }
}
```
