DEV Community

Jonathan Yeong
Jonathan Yeong

Posted on • Originally published at jonathanyeong.com on

Excerpts with Eleventy

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.

Top comments (3)

Collapse
 
jcubic profile image
Jakub T. Jankiewicz • Edited

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
Collapse
 
sjjensen profile image
sjjensen

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!

Collapse
 
djmtype profile image
Scott Rod • Edited

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