# Customizing the appearance of your site

Guide on how to use custom layouts to override single page elements and create fully custom content type layouts.

## Introduction

> [!NOTE]
> This tutorial assumes you have completed the [Creating your first site with Hinode](creating-first-site-hinode) tutorial.

Hinode uses Hugo's template lookup order to determine which layout files to use when rendering a page. By placing overrides in `layouts/[type]/`, you can change how individual elements — or entire pages — are rendered for a specific content type, without touching the default theme. In this guide, we will first override the header of a single page template, then define a fully custom layout for a new content type.

## Step 1 - Overriding the single page header

Hugo supports a comprehensive set of templates to generate the final site. Hinode splits the single page layout into three composable elements: `header`, `body`, and `footer`. Each element maps to a layout file in the `layouts/[type]/` folder.

### Understanding the template lookup order

Hinode v2 uses the [new template system introduced in Hugo v0.146.0](https://gohugo.io/templates/new-templatesystem-overview/). When Hugo renders a single page with `type: blog` set in frontmatter, it looks for templates under `layouts/blog/` first, falling back to the root `layouts/` directory. This means you only need to create the files that differ from Hinode's built-in templates.

The relevant lookup for a single page header looks as follows:

```text
layouts/
├── blog/
│   └── header.html     ← type-specific override (our file)
└── header.html         ← root-level fallback (provided by Hinode)
```

### Adding a type to a post

Add `type: blog` and an `author` field to the frontmatter of `content/posts/first-post.md`:

```yaml
---
type: blog
author: Ada Lovelace
---
```

> [!NOTE]
> The `posts` folder name does not automatically set the Hugo type — `type:` must be set explicitly in the frontmatter. Hugo uses the directory name as the section, which is separate from the type used for template lookup.

### Creating the custom header

Create `layouts/blog/header.html` with the following content. It renders the page title and, when present, an author line:

```go-html-template
{{ with .Title }}<p class="display-4 mt-5">{{ . }}</p>{{ end }}
{{ with .Params.author }}
  {{- $authorPage := $.Site.GetPage (printf "/contacts/%s" (urlize .)) -}}
  <div class="border-bottom mb-3">By {{ if $authorPage }}<a href="{{ $authorPage.Permalink }}">{{ . }}</a>{{ else }}{{ . }}{{ end }}</div>
{{ end }}
<p class="lead mb-5">{{ .Description }}</p>
```

The template uses Hugo's `Site.GetPage` to look up the contact page for the author. The `urlize` function converts the author name to a URL-safe slug — `"Ada Lovelace"` becomes `"ada-lovelace"` — matching the contact page path. If no contact page exists the name is rendered as plain text.

Save the file and open the first post in your browser. It should now display a linked author name beneath the title. Any other posts without `type: blog` continue to use the default header.

![Single page with custom header](img/custom-page.png)

## Step 2 - Creating a custom content type layout

In the previous step we overrode a single layout element. In this step we will go further and define a fully custom layout for a new content type called `contact`. The contact type renders a profile page that shows a responsive two-column layout on larger screens and a stacked layout on smaller screens.

### Adding a contact page

Create the folder `content/contacts/` and add a file `content/contacts/ada-lovelace.md` with the following content:

```yaml
---
title: Ada Lovelace
description: Mathematician and writer
type: contact
thumbnail: /img/logo512x512.png
---

Ada Lovelace is widely regarded as the first computer programmer.
She worked with Charles Babbage on the Analytical Engine
and published the first algorithm intended for a machine.
```

> [!NOTE]
> Hinode supports both a plain string and a nested object for `thumbnail`. The path `/img/logo512x512.png` is available from the Hinode theme — replace it with any square image of your choice.

### Creating the single page template

Create `layouts/contact/single.html`. This template defines the `main` block and controls the overall page structure. On smaller screens it shows the thumbnail separately above the content; on larger screens the two-column layout is handled by `body.html`:

```go-html-template
{{ define "main" -}}
    {{- $breakpoint := $.Scratch.Get "breakpoint" -}}
    {{- $padding := partial "utilities/GetPadding.html" -}}
    {{- $thumbnail := .Params.thumbnail -}}
    {{- if reflect.IsMap $thumbnail }}{{- $thumbnail = $thumbnail.url -}}{{- end -}}

    {{ .Render "header" }}

    <div class="container-xxl px-{{ $padding.x }} px-xxl-0 py-{{ $padding.y }} d-{{ $breakpoint.current }}-none">
        {{- partial "assets/live-image.html" (dict
            "src" $thumbnail
            "ratio" "1x1"
            "class" "rounded"
            "wrapper" "col-6 mx-auto"
            "title" .Title
        ) -}}
    </div>

    <div class="container-xxl flex-fill px-{{ $padding.x }} px-xxl-0">
        <div class="row row-cols-1 row-cols-{{ $breakpoint.current }}-2">
            <div class="col col-{{ $breakpoint.current }}-9">
                {{ .Render "body" }}
            </div>
        </div>
    </div>
{{ end -}}
```

### Creating the header template

Create `layouts/contact/header.html`. This renders the contact's name and role on smaller viewports. The desktop layout handles these inside the body column:

```go-html-template
{{- $breakpoint := $.Scratch.Get "breakpoint" -}}
{{- $padding := partial "utilities/GetPadding.html" -}}

<div class="container-xxl p-{{ $padding.x }} px-xxl-0 d-{{ $breakpoint.current }}-none mt-5">
    {{ with .Title }}<p class="display-5">{{ . }}</p>{{ end }}
    {{ with .Description }}<p class="lead"><strong>{{ . }}</strong></p>{{ end }}
</div>
```

### Creating the body template

Create `layouts/contact/body.html`. On desktop this shows the thumbnail, name, role, and content side by side. On mobile only the content body is rendered (the thumbnail is already shown by `single.html` above):

```go-html-template
{{- $breakpoint := $.Scratch.Get "breakpoint" -}}
{{- $padding := partial "utilities/GetPadding.html" -}}
{{- $thumbnail := .Params.thumbnail -}}
{{- if reflect.IsMap $thumbnail }}{{- $thumbnail = $thumbnail.url -}}{{- end -}}

<div class="d-none d-{{ $breakpoint.current }}-block my-{{ $padding.y }} pt-{{ $padding.y }}">
    <div class="row">
        <div class="col-4">
            {{- partial "assets/live-image.html" (dict
                "src" $thumbnail
                "ratio" "1x1"
                "class" "rounded"
                "title" .Title
            ) -}}
        </div>
        <div class="col-8">
            {{ with .Title }}<p class="display-5">{{ . }}</p>{{ end }}
            {{ with .Description }}<p class="lead"><strong>{{ . }}</strong></p>{{ end }}
            {{ with .Content }}<div class="lead mb-5 mt-3">{{ . }}</div>{{ end }}
        </div>
    </div>
</div>

<div class="d-{{ $breakpoint.current }}-none">
    {{ with .Content }}<div class="lead mb-5 mt-3">{{ . }}</div>{{ end }}
</div>
```

Navigate to `/contacts/ada-lovelace/` in your browser. The contact page should display a two-column layout with the profile photo alongside the text on wider screens:

![Custom contact page](img/custom-contact.png)

## Conclusion

In this guide we have customized the appearance of a Hinode site using two complementary techniques. We overrode a single layout element using the type-based template lookup, and defined a fully custom layout for a new content type. The [layout documentation](docs/configuration/layout/)
 provides more context about the available options and Hinode's layout conventions.
