Partials

Partials are first-class in Harp and work the same way across EJS and Jade. A partial can be included anywhere in an EJS or Jade file, and the rendered contents get mixed in.

Why?

To keep your app DRY, you need a way to reuse content. Partials provide a simple interface for great flexibility around reusing pieces of your project — headers, footers, navs, cards, anything that appears in more than one place.

Properties

The partial function takes two arguments:

  • path (String, required) — the relative path to the file to include, without the file extension.
  • data (Object, optional) — variables to mix into the partial.

Using Partials

Say you’re making a small website with an index.ejs file and an about.ejs file, and you want to include a header that repeats on every page. Put the header content in a file named _header.ejs and include it from both pages.

Because _header.ejs’s name begins with an underscore, it isn’t served directly. Instead, it’s included via the partial function.

The _header.ejs file can be as simple or complex as you’d like, for example:

<h1>This is my site</h1>
<p>This content is in a partial.</p>

Using partials in an EJS file

Inside index.ejs, call partial("_header") to include the content of _header.ejs:

<%- partial("_header") %>

Note the <%- %> tags (with the dash) — these output the partial unescaped, which is what you want for HTML. Using <%= %> (no dash) would HTML-escape the partial’s output, producing visible markup tags on the page. The same rule applies to yield inside layouts.

Now Harp will render index.ejs with the content from _header.ejs. You could repeat this for about.ejs, but what if the header should change between the two pages?

Update _header.ejs so the <h1> contains a title variable:

<h1><%= title %></h1>
<p>This content is in a partial.</p>

Then pass in the title when you call the partial:

<%- partial("_header", { title: "About me" }) %>

title is an arbitrary name — call it whatever fits the context. Multiple variables work too:

<%- partial("_header", { title: "About me", description: "This is my about page" }) %>

Using Partials in a Jade file

Using partials in Jade is very similar to EJS. Functions in Jade are prefixed with != rather than wrapped in <%- %>. Both forms render the partial unescaped:

!= partial("_header")

Jade may import EJS partials and vice versa. To pass data:

!= partial("_header", { title: "Contact me" })

Multiple values:

!= partial("_header", { title: "Contact me", description: "This is my Jade contact page with an EJS header" })

If you’d like to set fallbacks for your variables — in case you don’t pass any data into the partial — you can do this by setting global variables.

On Markdown and the `partial` function

You cannot call partial() from inside a .md file. The reason is structural: Markdown files are compiled to static HTML by marked, which is a Markdown renderer, not a template engine. It doesn’t execute template code, so functions like partial() (and EJS-style interpolation more generally) aren’t available inside a .md body. EJS and Jade are template engines and do execute template code, which is why these features work there.

What you can do:

Include a Markdown file as a partial from EJS or Jade. This works just like any other partial; the Markdown gets rendered to HTML and dropped in. With a _shared/an-example.md file:

<article><%- partial("_shared/an-example") %></article>
article!= partial("_shared/an-example")

Use the layout to add chrome around the markdown. A .md page is wrapped by the nearest _layout.ejs, which runs as a normal EJS template — so all the variables, partials, and template logic you need can live in the layout. The body of the .md file stays pure prose.

If you genuinely need a partial inside the body of a content page, convert that page from .md to .ejs.