How to Use Excerpts in Eleventy
Tags: javascript, eleventy, jamstack
Published: 2020-09-04 16:40:42

---
title: How to Use Excerpts in Eleventy
published: true
date: 2020-08-08 00:00:00 UTC
tags: ["javascript", "eleventy", "JAMstack"]
canonical_url: https://webbureaucrat.gitlab.io/posts/eleventy-excerpts/
---

Recently, I added first-paragraph [post excerpts](https://www.11ty.dev/docs/data-frontmatter-customize/) to [this Eleventy blog's homepage](https://webbureaucrat.gitlab.io/) post list. I found it wasn't as easy as I expected. It wasn't all documented all in one place. Further, in order to use Markdown excerpts in HTML, I had to write a simple custom filter. I'd like to document the process here from end to end.

### Enable `grey-matter` excerpts in _.eleventy.js_.

The first thing we need is to configure Eleventy to be able to see our excerpts. This is easily done by adding this line to the _.eleventy.js_ configuration file into the main `module.exports = function(eleventyConfig) { ... }` function.

```js
eleventyConfig.setFrontMatterParsingOptions({ excerpt: true });
```

### Optional: Set the excerpt separator

The excerpt separator is some string which marks the end of the excerpt and the beginning of the rest of the article. By default, it is "---" but this default is easily overridden using the optional `excerpt_separator` property of the Front Matter parsing options object, like so:

```js
eleventyConfig.setFrontMatterParsingOptions({ excerpt: true,
                                              excerpt_separator: "--excerpt--" 
                                            });
```

### Add excerpt separators into each post

Now you can mark each post with excerpt separators. I use the default "---", but you can use whatever `excerpt_separator` you may have overridden it within the previous step.

### Write a simple custom filter to read Markdown excerpts

At this point, we need to reconcile a potential conflict. In my case at least,I am writing blog posts in markdown, but my post list on the homepage is a _.njk_ that compiles to HTML. I don't want to change either of those things, but if I reference my markdown excerpts in HTML, they'll show up as raw markdown text. I need to write a bit of middleware to reconcile the two.

Start by locating your markdownIt options object. You'll find it in a block of code that looks something like this:

```js
let markdownLibrary = markdownIt({ html: true, 
                                   breaks: false, 
                                   linkify: true 
                                 });
eleventyConfig.setLibrary("md", markdownLibrary);
```

You'll need to reuse this object, so it's a good practice to separate it into its own constant at the top of the file...

```js
const MARKDOWN_OPTIONS = { html: true, 
                           breaks: false, 
                           linkify: true 
                         };
```

...that can be referenced in multiple places

```js
let markdownLibrary = markdownIt(MARKDOWN_OPTIONS);
eleventyConfig.setLibrary("md", markdownLibrary);
```

This is all in the service of writing a simple custom filters that can take markdown strings and turn them into HTML fragments. This will do it for us.

```js
eleventyConfig.addFilter("toHTML", str => 
  { 
    return new markdownIt(MARKDOWN_OPTIONS).renderInline(str);
  });
```

### Use the custom filter to display the HTML excerpts in your post lists

Now, finally, I can include this excerpt in my _/\_includes/postlist.njk_,which iterates over the `posts` collection like so:

(Fair warning: I formatted this for readability. If you copy/paste this, you may see some whitespace issues to fix.)

```html
{% for post in postslist | reverse %} 
  <li class="postlist-item{% if post.url == url %} postlist-item-active{% endif %}"> 
    <h2 class="h2-postlist">
      <a href="{{ post.url | url }}" 
         class="postlist-link"> 
        {% if post.data.title %}
          {{ post.data.title }} 
        {% else %}
          <code>{{ post.url }}</code> 
        {% endif %} 
      </a> 
    </h2> 
    <time class="postlist-date" 
          datetime="{{ post.date | htmlDateString }}"> 
      {{ post.date | htmlDateString }} 
    </time> 
    {% for tag in post.data.tags %} 
      {%- if collections.tagList.indexOf(tag) != -1 -%} 
        {% set tagUrl %}/tags/{{ tag }}/{% endset %} 
        <a href="{{ tagUrl | url }}" class="tag">{{ tag }}</a> 
      {%- endif -%} 
    {% endfor %} 
  </li> 
{% endfor %}
```

Let us pipe the post excerpt into our `toHTML` custom filter and then pipe the output of our filter to the built-in `safe` filter so that Eleventy treats the output as HTML instead of plain text.

```html
{% for post in postslist | reverse %} 
  <li class="postlist-item{% if post.url == url %} postlist-item-active{% endif %}"> 
    <h2 class="h2-postlist"> 
      <a href="{{ post.url | url }}" 
         class="postlist-link"> 
        {% if post.data.title %}
          {{ post.data.title }} 
        {% else %}
          <code>{{ post.url }}</code> 
        {% endif %} 
      </a> 
    </h2> 
    <time class="postlist-date" 
          datetime="{{ post.date | htmlDateString }}"> 
      {{ post.date | htmlDateString }} 
    </time> 
    {% for tag in post.data.tags %} 
      {%- if collections.tagList.indexOf(tag) != -1 -%} 
        {% set tagUrl %}/tags/{{ tag }}/{% endset %} 
        <a href="{{ tagUrl | url }}" 
           class="tag">{{ tag }}
        </a> 
      {%- endif -%} 
    {% endfor %} 
    {%- if post.data.page.excerpt -%} 
      <p>{{ post.data.page.excerpt | toHTML | safe}}</p> 
    {%- endif -%} 
  </li> 
{% endfor %}
```

And now when we run `npx eleventy --serve` we should see our excerpts everyplace we reference _\_includes/postlist.njk_. 

[Click here](https://webbureaucrat.gitlab.io/) for a live demo.