Excerpts with Eleventy
Jonathan Yeong

Jonathan Yeong @jonathanyeong

About: Staff Software Dev originally from Australia - Ruby on Rails is my bread and butter - Helping other devs is my jam.

Location:
Toronto, Canada
Joined:
Jan 6, 2017

Excerpts with Eleventy

Publish Date: Aug 28 '20
9 3

I 100% struggled with getting excerpts in Eleventy (11ty). It seems so simple, but I couldn’t figure it out.

I had two issues. Firstly, I got excerpts working using 11ty’s custom frontmatter data, unfortunately the excerpt did not render markdown. Which resulted in something that looked like this:

raw markdown

Secondly, I found a great blog post: Creating a blog with Eleventy that detailed how to create an excerpt shortcode. This shortcode defaulted to taking the first paragraph as an excerpt. Or whatever custom excerpt tag you wanted. However, the shortcode ended up rendering the HTML tags. The opposite problem to 11ty’s excerpt. Rendering HTML resulted in some weird looking excerpts:

rendered html tags

I could not find a happy medium! Here’s what I really wanted out of an excerpt:

  • Cap at 200 characters
  • Strip any HTML tags.
  • Add an ellipses at the end of the excerpt
  • Automatically pull the excerpt, no need for specific tags.

Thankfully, the blog post above gave me all the code I needed. I just had to make a few modifications.

The modifications to extractExcerpt

First, install striptags. We will be using this library to get rid of the HTML tags:

npm install striptags
Enter fullscreen mode Exit fullscreen mode

Now, we want to require striptags in .eleventy.js. At the top of the file:

const striptags = require("striptags");
Enter fullscreen mode Exit fullscreen mode

Next, add the extractExcerpt method at the bottom of the .eleventy.js file. This method is a modified version from the blog post to fit the criteria I wanted:

function extractExcerpt(article) {
  if (!article.hasOwnProperty("templateContent")) {
    console.warn(
      'Failed to extract excerpt: Document has no property "templateContent".'
    );
    return null;
  }

  let excerpt = null;
  const content = article.templateContent;

  excerpt = striptags(content)
    .substring(0, 200) // Cap at 200 characters
    .replace(/^\\s+|\\s+$|\\s+(?=\\s)/g, "")
    .trim()
    .concat("...");
  return excerpt;
}
Enter fullscreen mode Exit fullscreen mode

Add this line in the eleventyConfig block. This step is also from the blog post:

module.exports = function(eleventyConfig) {
  eleventyConfig.addShortcode("excerpt", (article) => extractExcerpt(article));

  ...
}
Enter fullscreen mode Exit fullscreen mode

Finally, we can see our results.

Final results

Hooray! Nothing looks too off. I do see Addendum # which is caused by markdownIt adding an anchor permalink to the header. I can live with it though.

Looking back on this problem, the solution seems so easy. But I spent almost a week trying to figure out how to do this properly. I think it’s a combination of being stubborn with wanting the 11ty custom frontmatter solution to work, and my inability to Google. Really need to Google or ask for help sooner. I don’t know about you, but knowing when to ask for help is an endless struggle for me. Bar this one issue, I’m loving 11ty so far! Hopefully, this post will solve your excerpt woes.

Comments 3 total

  • Scott Rod
    Scott RodDec 3, 2020

    For liquid and nunjucks, add {% excerpt post %} to your template.

  • sjjensen
    sjjensenSep 23, 2021

    Thanks for this! It was a snap to configure. But I'd like to customize it a bit.

    I have two collections. Any way to add an if statement so it only grabs the excerpt for a particular collection?

    Thanks!

  • Jakub T. Jankiewicz
    Jakub T. JankiewiczJul 9, 2023

    I prefer what is suggested by Jekyll to add <!-- more --> and extract content before this comment. So you're in control what is in the excerpt.

    I use this code:

        eleventyConfig.addShortcode("intro", function(article) {
            const content = article.templateContent;
            const m = content.match(/([\s\S]+)<!-- more -->/);
            if (m) {
                return striptags(m[1]).trim();
            }
            return content;
        });
    
    Enter fullscreen mode Exit fullscreen mode
Add comment