Right, so you’ve got Hugo’s default Markdown rendering humming along, and it’s… fine. Perfectly serviceable. But you’re not here for ‘serviceable,’ are you? You want to bend the output to your will, to inject your own style and logic into the very atoms of your page. That’s where render hooks come in, and today we’re talking about the blockquote. It’s the perfect place to start—it seems simple, but oh, the things you can do.

Think about a standard Markdown blockquote: > A quote. Hugo turns it into a <blockquote><p>A quote</p></blockquote>. It’s semantically correct, but it’s also a blank canvas. With a blockquote render hook, you can seize control of that entire process. Want to automatically attribute quotes? Style them with specific CSS classes? Parse the content for a citation and format it magically? Strap in.

The Nuts and Bolts of the File

First, you have to create the right file in the right place. Hugo is notoriously opinionated about this. You’ll create a file at layouts/_default/_markup/render-blockquote.html inside your project. The _default part means this is your site-wide template for blockquotes. If you want to get fancy and have a different style for a specific content type, you could place it under layouts/blog/... instead, but let’s start simple.

The magic here is that this isn’t just a template; it’s a template that gets passed a context object. You access this context with a . dot. The most important attribute you’ll use is .Text, which is the rendered HTML content inside the blockquote (already processed from Markdown into HTML, so that **bold** is already a <strong>bold</strong>).

Here’s the most basic render hook, which essentially replicates Hugo’s default behavior:

<blockquote>
  {{ .Text }}
</blockquote>

It’s almost comically simple. But the power isn’t in recreating the default; it’s in what you add around that .Text.

A Practical Example: Adding a Dash of Style

Let’s say your design system uses a lovely border and a subtle background for blockquotes. Instead of manually adding a class every time you write >, you can bake it right into the component.

<blockquote class="bg-slate-50 px-6 py-4 border-l-4 border-slate-400 italic my-8">
  {{ .Text }}
</blockquote>

Now, every single blockquote on your site gets this treatment automatically. Consistency, achieved. This is the simplest and most common use case: wrapping the content in more specific HTML.

Leveling Up: The Slightly Absurd (But Useful) Citation Hack

Here’s where we get clever. Imagine you always write your quotes with an attribution dash at the end, like > The best way to predict the future is to invent it. - Alan Kay. We can write a render hook that parses that .Text, finds the dash, and splits the quote from the attribution. It’s a bit of a hack, I’ll be honest—the template language isn’t exactly built for complex string parsing—but it’s a brilliant demonstration of power.

{{ $text := .Text | safeHTML }}
{{ if findRE " - " $text }}
  {{ $parts := split $text " - " }}
  <blockquote class="my-quote">
    <p class="quote-content">{{ index $parts 0 | safeHTML }}</p>
    <footer class="quote-attribution">— {{ index $parts 1 }}</footer>
  </blockquote>
{{ else }}
  <blockquote class="my-quote">
    {{ $text }}
  </blockquote>
{{ end }}

Let’s be direct about the rough edges here. This is fragile. If your quote has a dash in the actual quote text, this will break horribly. It’s a classic case of a “questionable choice” that works perfectly if you strictly control your content format. For a personal blog where you’re the only author, it’s a neat trick. For a multi-author site, it’s a potential nightmare. Best practice? Use it cautiously, or better yet, consider a more robust solution like a shortcode for quotes that need attribution.

The Golden Rule: You Must Escape (Or Not)

This is the pitfall. Notice the | safeHTML in the example above? .Text is already rendered HTML. When you start manipulating it with functions like split, the Go template engine will escape the HTML characters (< becomes &lt;) as a security measure. Using safeHTML tells Hugo, “I know what I’m doing, this is already valid HTML, please output it as-is.”

You must do this if you manipulate the string. If you don’t, your readers will see actual <p> tags on the page. However, only use safeHTML on content you absolutely trust, because it will render any HTML/JS inside it. If you’re parsing user-generated content, this is a massive XSS risk. For your own site, it’s fine. For anything else, tread carefully.

The blockquote render hook is your gateway drug to the world of custom Markdown rendering. It teaches you the core concepts: finding the file, using the context object, and manipulating the output. Start here, make your quotes beautiful, and then go take over the rest of the rendering pipeline.