Skip to content

Layouts

Devin edited this page Jun 29, 2020 · 7 revisions

Layouts let you to define shared HTML used by your pages. For example, a main layout can contain the header and footer of your site, so that you can focus on the content of each page instead of including these elements everywhere.

Configuration

By default, Frontman assumes your layouts are located in the views/layouts/ directory. You can change the location Frontman should look in by setting the :layout_dir configuration value in your config.rb.

Frontman::Config.set :layout_dir, 'my-layout-dir/'

Defining layouts

There are two ways you can define what layout Frontman must use to render your page: globally (based on the URL) or via a YAML front matter. By default, when you initialize a new Frontman project, we add a line to your config.rb that renders all your pages using the main.haml layout.

Defining layouts globally

You can define the layout for your pages globally, based on the URL structure. For example, if you have a blog and you want to use the views/layouts/blog_post.haml layout to render all the pages under posts/, you can register this layout in your config.rb file:

register_layout 'posts/*', 'blog_post.haml'

Frontman uses glob matching to find the first matching layout for any page. If you register a layout with '*' as the URL pattern, make sure to register it last so that it doesn't override other, more specific layouts.

Defining layouts via front matter

You can use YAML front matter in your pages to define a layout key with the relative path to your layout. By default, Frontman looks for layouts in the views/layouts/ directory.

---
layout: blog_post.haml
---

The layout you define in the front matter takes precedence over any matching layout registered in your config.rb file. Therefore, you should only use layout definitions in front matter as an exception, and prefer to define your layouts globally when possible.

Extending layouts

You can extend layouts by wrapping them within each other with the wrap_layout method. Consider the following layouts in your project:

-# views/layouts/main.haml

%html
  %head
   %title
     My site
  %body
    = yield
-# views/layouts/blog_post.haml

= wrap_layout 'main.haml' do
  %article.content
    = yield

And imagine we have the following source/posts/my-first-post.html.md page:

Hello, world!

If we register blog_post.haml as the layout for all our posts, Frontman generates the following HTML for my-first-post.html.md.

<html>
  <head>
    <title>My site</title>
  </head>
  <body>
    <article class="content">
      <p>Hello, world!</p>
    </article>
  </body>
</html>

Layout slots

Sometimes, you need to forward data from a page to the layout you render it in. You can do this using the yield_content, content_for?, and content_for methods.

In your pages and layouts, you can define content for content slots using the content_for method:

<% content_for :page_title, current_page.data.title %>

You can use the content_for? method to check if there is any content for a given slot.

content_for? :page_title # false

content_for :page_title, 'Hello, world!'
content_for? :page_title # true

Finally, in your layouts, you can use yield_content to output the content for a given block.

content_for :page_title, 'Hello, world!'

puts yield_content :page_title # outputs "Hello, world!"

You can leverage content blocks, for example, to set the page title from a page's front matter. In your main layout, you can use yield_content if the page title is set.

%html
  %head
   %title
     = content_for?(:page_title) ? yield_content(:page_title) : 'Welcome'
  %body
    = yield

Then, in views/layouts/blog_post.haml, you can define the content block with content_for.

- content_for :page_title, current_page.data.title # current_page.data.title is the `title` property in your page's front matter
= wrap_layout 'main.haml' do
  %article.content
    = yield

Finally, in source/posts/my-first-post.html.md, you can set the title property in the front matter.

---
title: This is the title of my page!
---

Hello, world!

This results in the following HMTL:

<html>
  <head>
    <title>This is the title of my page!</title>
  </head>
  <body>
    <article class="content">
      <p>Hello, world!</p>
    </article>
  </body>
</html>