diff --git a/docs/content/en/content-management/shortcodes.md b/docs/content/en/content-management/shortcodes.md
index 8e345f2fb36..7a589a34008 100644
--- a/docs/content/en/content-management/shortcodes.md
+++ b/docs/content/en/content-management/shortcodes.md
@@ -94,6 +94,40 @@ Example usage:
Although you can call this shortcode using the `{{* */>}}` notation, computationally it is more efficient to call it using the `{{%/* */%}}` notation as shown above.
+### details
+
+{{< new-in 0.140.0 >}}
+
+{{% note %}}
+To override Hugo's embedded `details` shortcode, copy the [source code] to a file with the same name in the layouts/shortcodes directory.
+
+This may be useful if you are wanting access to more global HTML attributes.
+
+[source code]: {{% eturl details %}}
+{{% /note %}}
+
+Use the `details` shortcode to generate a collapsible details HTML element. For example:
+
+```text
+{{* details summary="Custom Summary Text" */>}}
+Showing custom `summary` text.
+{{* /details */>}}
+```
+
+Additional examples can be found in the source code. The `details` shortcode can use the following named arguments:
+
+summary
+: (`string`) Optional. Specifies the content of the child summary element. Default is "Details"
+
+open
+: (`bool`) Optional. Whether to initially display the contents of the details element. Default is `false`.
+
+name
+: (`string`) Optional. The value of the element's name attribute.
+
+class
+: (`string`) Optional. The value of the element's class attribute.
+
### figure
{{% note %}}
diff --git a/docs/data/embedded_template_urls.toml b/docs/data/embedded_template_urls.toml
index 38b437fe15d..b7247f2727f 100644
--- a/docs/data/embedded_template_urls.toml
+++ b/docs/data/embedded_template_urls.toml
@@ -25,6 +25,7 @@
# Shortcodes
'comment' = 'shortcodes/comment.html'
+'details' = 'shortcodes/details.html'
'figure' = 'shortcodes/figure.html'
'gist' = 'shortcodes/gist.html'
'highlight' = 'shortcodes/highlight.html'
diff --git a/tpl/tplimpl/embedded/templates/shortcodes/details.html b/tpl/tplimpl/embedded/templates/shortcodes/details.html
new file mode 100644
index 00000000000..932289517a6
--- /dev/null
+++ b/tpl/tplimpl/embedded/templates/shortcodes/details.html
@@ -0,0 +1,68 @@
+{{- /*
+Renders an HTML details element.
+
+@param {string} [summary] The content of the child summary element.
+@param {bool} [open=false] Whether to initially display the contents of the details element.
+@param {string} [class] The value of the element's class attribute.
+@param {string} [name] The value of the element's name attribute.
+
+@reference https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details
+
+@examples
+
+ {{< details >}}
+ A basic collapsible section.
+ {{< /details >}}
+
+ {{< details summary="Custom Summary Text" >}}
+ Showing custom `summary` text.
+ {{< /details >}}
+
+ {{< details summary="Open Details" open=true >}}
+ Contents displayed initially by using `open`.
+ {{< /details >}}
+
+ {{< details summary="Styled Content" class="my-custom-class" >}}
+ Content can be styled with CSS by specifying a `class`.
+
+ Target details element:
+
+ ```css
+ details.my-custom-class { }
+ ```
+
+ Target summary element:
+
+ ```css
+ details.my-custom-class > summary > * { }
+ ```
+
+ Target inner content:
+
+ ```css
+ details.my-custom-class > :not(summary) { }
+ ```
+ {{< /details >}}
+
+ {{< details summary="Grouped Details" name="my-details" >}}
+ Specifying a `name` allows elements to be connected, with only one able to be open at a time.
+ {{< /details >}}
+
+*/}}
+
+{{- /* Get arguments. */}}
+{{- $summary := or (.Get "summary") (T "shortcodes.details") "Details" }}
+{{- $class := or (.Get "class") "" }}
+{{- $name := or (.Get "name") "" }}
+{{- $open := false }}
+{{- if in (slice "false" false 0) (.Get "open") }}
+ {{- $open = false }}
+{{- else if in (slice "true" true 1) (.Get "open")}}
+ {{- $open = true }}
+{{- end }}
+
+{{- /* Render. */}}
+{{ $summary | .Page.RenderString }}
+ {{ .Inner | .Page.RenderString (dict "display" "block") -}}
+
ac
") } + +func TestDetailsShortcode(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.toml -- +disableKinds = ['rss','section','sitemap','taxonomy','term'] +defaultContentLanguage = "en" +[languages] + [languages.en] + weight = 1 + [languages.es] + weight = 2 +-- i18n/en.toml -- +[shortcodes.details] +other = "Details" +-- i18n/es.toml -- +[shortcodes.details] +other = "Detalles" +-- layouts/_default/single.html -- +{{ .Content }} +-- content/d1.md -- +--- +title: Default State Test +--- +{{< details >}} +Basic example without summary +{{< /details >}} +-- content/d2.md -- +--- +title: Custom Summary Test +--- +{{< details summary="Custom Summary" >}} +Example with custom summary text +{{< /details >}} +-- content/d3.md -- +--- +title: Open State Test +--- +{{< details summary="Test Open State" open="true" >}} +Example with open state +{{< /details >}} +-- content/d4.md -- +--- +title: Attributes Test +--- +{{< details summary="Test Attribute sanitization" style="color: red; font-weight: bold; background-color: #eee" onclick="alert('test')" >}} +Example testing attribute sanitization +{{< /details >}} +-- content/d5.md -- +--- +title: Class Test +--- +{{< details class="custom-class" >}} +Example with allowed class attribute +{{< /details >}} +-- content/d6.md -- +--- +title: Name Test +--- +{{< details name="custom-name" >}} +Example with allowed name attribute +{{< /details >}} +-- content/d7.es.md -- +--- +title: Localization Test +--- +{{< details >}} +Localization example without summary +{{< /details >}} +` + b := hugolib.Test(t, files) + + // Test1: default state (closed by default) + b.AssertFileContentEquals("public/d1/index.html", + "\nBasic example without summary
\nExample with custom summary text
\nExample with open state
\nExample testing attribute sanitization
\nExample with allowed class attribute
\nExample with allowed name attribute
\nLocalization example without summary
\n