Skip to main content

How to use <details> <summary> expandable content with Hugo

··1082 words·6 mins
Hugo Shortcode
Race Dorsey
Author
Race Dorsey
Table of Contents

UPDATE: Hugo has added a details shortcode in version 0.140.0. If you are just needing a basic details shortcode then use hugo version to check what version you are on. The below article implements a slightly more advanced details shortcode, as well as touches on how to style it.

Learn how to create a details shortcode in Hugo

In HTML <detail> and <summary> tags can be used to collapse sections of text that a reader can choose to expand. This is useful to include technical details or other content that not every user may appreciate but the information will be available for those who are interested. These tags, however, do not work natively in markdown meaning Hugo can’t use <detail> and <summary> directly but can be used as a shortcode. In this article we will be creating our own details shortcode.

Here is an example of what we will be building:

Details

This is the first paragraph of detailed content. This is the second paragraph of even more detailed content.

  • You can also include lists
  • Or other markdown elements

Create details.html
#

Create the following file in the specified directory relative to your project folder.

layouts/shortcodes/details.html:

{{- /* Get arguments. */}}
{{- $summary := or (.Get "summary") (T "details") "Details" | .Page.RenderString }}
{{- $altSummary := or (.Get "altSummary") $summary | .Page.RenderString }}
{{- $open := false }}
{{- with .Get "open" }}
    {{- if not (eq . false) }}
        {{- $open = true }}
    {{- end }}
{{- end }}
{{- $attributes := dict }}
{{- range $key, $value := .Params }}
    {{- if not (in (slice "summary" "altSummary" "open") $key) }}
        {{- $attributes = merge $attributes (dict (string $key) $value) }}
    {{- end }}
{{- end }}

{{- /* Render. */}}
<details
    {{- if $open }} open {{- end -}}
    {{- range $key, $value := $attributes }} {{ $key }}="{{ $value }}"{{- end }}
>
<summary onclick="this.innerHTML = this.parentNode.open ? '{{ $summary }}' : '{{ $altSummary }}';">
    {{ if $open }}
        {{ $altSummary }}
    {{ else }}
        {{ $summary }}
    {{ end }}
</summary>
    {{ .Inner | .Page.RenderString (dict "display" "block") }}
</details>

Arguments:
#

When using this shortcode there are several arguments:

  1. summary (str). Default = “Details:”. This is the text that appears for users to click on.
  2. open (bool). Default = false. If this argument is specified, and a value other than false (bool) is provided, then the element will be expanded upon page load.
  3. altSummary (str). Default = summary. This is the text that appears when the details tag is open. If not provided it will be the same as the summary text.
  4. […params] (object) Additional HTML attributes passed directly to the details element. Such as class or name.

Usage:
#

Within your markdown, you can now use this as a shortcode as follows:

{{< details >}}
This is the first paragraph of detailed content.
This is the second paragraph of even more detailed content.
- You can also include lists
- Or other markdown elements
{{< /details >}}
Details

This is the first paragraph of detailed content. This is the second paragraph of even more detailed content.

  • You can also include lists
  • Or other markdown elements

It is important to remember to call the shortcode, type your text, and then close the shortcode.

Using summary
#

Below is an example with specifying the summary name.

{{< details summary="Super Secret Text" >}}
Enter your super secrets here
{{< /details >}}
Super Secret Text

Enter your super secrets here

Using open
#

Here is an example specifying the content to be expanded when the page loads.

{{< details summary="Super Secret Text" open=true >}}
Oh no, my secrets are out! 
{{< /details >}}
Super Secret Text

Oh no, my secrets are out!

Using altSummary
#

The below example specifies an alternate summary for when the details element is open

{{< details summary="Super Secret Text" open=false altSummary="click to close before anyone sees!" >}}
Oh no, my secrets are out! 
{{< /details >}}
Super Secret Text

Oh no, my secrets are out!

Using name
#

Below we will specify three details elements, all with the same name. They can still have different summaries and text within them, however, since they will have the same name only one element will be able to be open at a time.

{{< details summary="Planning" name="name demonstration" >}}
Planning text
{{< /details >}}
{{< details summary="Designing" name="name demonstration" >}}
Designing text
{{< /details >}}
{{< details summary="Implementation" name="name demonstration" >}}
Implementation text
{{< /details >}}

Planning

Try opening “Designing”

Designing

Try opening “Implementation

Implementation

Try opening “Planning”

As you can see, only one of the “Planning”, “Designing”, “Implementation” elements can be open at the same time.

Additional Usage
#

This shortcode has a few additional features:

Specifying named arguments in any order
#

The details shortcode can accept any of the named arguments in any order. Such as:

{{< details altSummary="This is my alt summary even though listed first" open=false  summary="This is my summary even though listed last" >}}
See, order does not matter when passing named arguments
{{< /details >}}
This is my summary even though listed last

See, order does not matter when passing named arguments

Using only some arguments
#

In some of our first examples we used no arguments and later started passing additional arguments. You are able to pass any number of arguments.

{{< details altSummary="Only One Argument" >}}
Here I only passed 1 named argument, the `altSummary`  
{{< /details >}}
Details

Here I only passed 1 named argument, the altSummary

Styling
#

Since we are able to pass any attribute to the HTML, this includes class. If you want to add styling to your details elements then you can select them with CSS. To do this you will need to load a CSS stylesheet. Within it you can use the following to select different parts of the details element. Suppose you want to modify my-custom-class:

/*Target details element*/
details.my-custom-class { }

/*Target summary element*/
details.my-custom-class > summary > * { }

/*Target inner content*/
details.my-custom-class > :not(summary) { }

Using Headers in details elements
#

If you intend to use headers in your summaries, then you will want to make the summaries appear inline. This is because headers are block elements that naturally begin on a new line and will appear a line lower than where the details element starts. To fix this for your my-custom-class you can use the following:

details.my-custom-class > summary > * {
  display: inline;
}