Layouts
A Layout is a common template that includes all content except for one main content area. You can think of a Layout as the inverse of a partial
.
Why?
Often sites and apps will have common headers and footers and the only area that needs to change is the body. This is an ideal use case for a layout.
Usage
A Layout requires a layout file, written in EJS or Jade, and a yield
property to tell Harp where to insert the content.
Example using EJS Templating
Given a really simple app / project with this structure:
myapp.harp.io/
|- _layout.ejs
+- index.ejs
_layout.ejs
<html>
<head>
<title>My Site</title>
<script src="/javascripts/jquery.js">
</script><script src="/javascripts/app.js"></script>
</head>
<body>
<%- yield %>
<div id="footer">
<p>Copyright © foobar</p>
</div>
</body>
</html>
index.ejs
<h1>My Site</h1>
<p>Welcome to my very first site.</p>
The final result:
<html>
<head>
<title>My Site</title>
<script src="/javascripts/jquery.js">
</script><script src="/javascripts/app.js"></script>
</head>
<body>
<h1>My Site</h1>
<p>Welcome to my very first site.</p>
<div id="footer">
<p>Copyright (c) foobar</p>
</div>
</body>
</html>
Example using Jade Templating
Harp allows you to apply a .jade
file extension on your layout as well. Mixing and matching templates is also acceptable such as in the following case where we have a _layout.jade
and index.ejs
.
Given a really simple app / project with this structure:
myapp.harp.io/
|- _layout.jade
+- index.jade
_layout.jade
doctype
html
head
title My Site
script(src="/javascripts/jquery.js")
script(src="/javascripts/app.js")
body
!= yield
#footer
p Copyright (c) foobar
index.jade
h1 My Site
p Welcome to my very first site.
The final result:
<html>
<head>
<title>My Site</title>
<script src="/javascripts/jquery.js">
</script><script src="/javascripts/app.js"></script>
</head>
<body>
<h1>My Site</h1>
<p>Welcome to my very first site.</p>
<div id="footer">
<p>Copyright (c) foobar</p>
</div>
</body>
</html>
Multiple Layouts
You can take advantage of Layouts in multiple locations through your application. In the following example, there is a directory of articles which you’d like to have a different layout than on the main page of your site.
myapp.harp.io/
|- _layout.ejs
|- index.ejs
|- about.md
+- articles/
|- _layout.ejs
|- article-one.md
+- article-two.md
Here, index.ejs
and about.md
will use the _layout.ejs
file in the root of the app. Anything in the articles directory—in this case, article-one.md
and article-two.md
—will use the _layout.ejs
in the same directory.
Explicit Layouts
Layouts other than _layout
can be specified in a _data.json
. This is useful if you need even finer control of Layouts, or if you want to name your Layout something other than _layout
.
myapp.harp.io/
|- _layout.ejs
|- index.ejs
|- about.md
+- articles/
|- _data.json
|- _an-example-layout.ejs
|- _another-one.jade
|- article-one.md
+- article-two.md
Here, it’s possible to make article-one.md
use _an-example-layout.ejs
by specifying layout
in the _data.json
file in that folder:
{
"article-one": {
"layout": "_an-example-layout",
"title": "Example Title"
},
"article-two": {
"layout": "_another-one",
"title": "Another Example Title"
}
}
Now, each article will use the specified Layout.
Opt out of a Layout
It’s possible for a file to be exempt from Layouts by using "layout": false
.
Take the following app as an example:
myapp.harp.io/
|- _data.json
|- _layout.ejs
|- index.ejs
+- about.md
Adding the following to the _data.json
file will make about.md
render as plain HTML, never passing through a layout.
{
"about": {
"layout": false
}
}
Since this has only been specified for the About page, index.ejs
will continue to use _layout.ejs
as a Layout.
Nested Layouts
If you are taking advantage of Harp’s built-in support for Jade, you may use Jade’s Block and Extends features to create nested layouts.
Harp itself doesn’t have a built-in way to create nested layouts, as [partial()
] already provides ways around this. For example, _layout.ejs
might look like this:
<!-- If the current page is blog/ but not blog/index.ejs… -->
<% if(current.path[0] == "blog" && current.source !== 'index') { %>
<!-- Render the partial blog/_nest -->
<%- partial(current.path[0] + "/_nest") %>
<% } else { %>
<!-- Otherwise, render the yield -->
<%- yield %>
<% } %>
This allows you to put a _nest.ejs
partial into the blog/
directory, giving you the opportunity to create a nested layout. By including [yield
] in the _nest.ejs
partial, the contents of the page you’re trying to render will be available in this _nest.ejs
partial. For example, blog/_nest.ejs
might look like this:
<article>
<%- yield %>
</article>
Now, the blog/
index page will render normally, while any blog posts like blog/hello-world
will have their contents wrapped in the <article>
tag you specified in the partial. There is a full example of this on the hb-simurai Harp boilerplate, which you can try out by running the following command:
harp init -b kennethormandy/hb-simurai my-nested-example
Note that the _nest.ejs
file could be named anything you’d like, it is simply a regular partial.