How to Make a Collapsible Section in Markdown
Markdown has no collapsible syntax, so you borrow HTML's <details> element. This guide covers the syntax, the blank-line rule that decides whether the Markdown inside renders at all, and the native alternatives in Obsidian, Notion, and MkDocs.
Short answer
Wrap the content in <details> and put the clickable label in <summary>. Leave a blank line after the closing </summary> tag — without it the Markdown inside is printed as raw text instead of being formatted. Add open to start it expanded.
<details>
<summary>Click to expand</summary>
Hidden content goes here, and it can use **Markdown**.
</details>The <details> Syntax
There is no collapsible section in the Markdown spec, and there never has been. What every guide calls “Markdown collapsible sections” is the HTML <details> element, which works because CommonMark deliberately lets raw HTML through. It is three parts:
<details>— the container. Everything between the tags is what collapses.<summary>— the always-visible label the reader clicks. Optional, but without one the browser shows a bare “Details” triangle.- A blank line after
</summary>— the part everyone forgets. See the next section.
Markdown
<details>
<summary>Click to expand</summary>
Hidden content goes here, and it can use **Markdown**.
</details>Preview (click it)
Click to expand
Hidden content goes here, and it can use Markdown.
<details> is passed straight through by the renderer, every preview pane on this page is a working disclosure widget — click one and it opens, the same way it will on GitHub.The Blank-Line Rule
This is the reason collapsible sections go wrong, and almost nothing that ranks for this topic says it out loud. In CommonMark, an HTML block runs until the first blank line. Everything before that blank line is copied to the output untouched — so if your content is pressed up against </summary>, it is still inside the raw HTML, and the parser never sees the asterisks as bold.
Markdown
<details>
<summary>Click to expand</summary>
This line uses **Markdown**.
</details>HTML output
<details>
<summary>Click to expand</summary>
This line uses **Markdown**.
</details>Markdown
<details>
<summary>Click to expand</summary>
This line uses **Markdown**.
</details>HTML output
<details>
<summary>Click to expand</summary>
<p>This line uses <strong>Markdown</strong>.</p>
</details>The blank line that matters is the one after </summary>. A blank line before </details> is optional in CommonMark and on GitHub, because a closing HTML tag can end a paragraph on its own. It is still worth adding: GitLab's documentation recommends it and it keeps the source readable.
Starting It Expanded
Add the open attribute to the opening tag. It is a boolean attribute — it takes no value — and the reader can still collapse the section afterwards.
Markdown
<details open>
<summary>Already expanded</summary>
The reader can still collapse this one.
</details>Preview (click it)
Already expanded
The reader can still collapse this one.
readme_renderer, whose allow-list permits the <details> and <summary> tags but allows only id as a generic attribute. So open is stripped and the section arrives collapsed. Never put the thing a reader must see behind a toggle.Accordion: One Section Open at a Time
Give several <details> blocks the same name and the browser treats them as a group: opening one closes the others. No JavaScript, and current versions of Chrome, Edge, Firefox, and Safari all support it. Try it in the preview.
Markdown
<details name="faq">
<summary>What does it cost?</summary>
Nothing.
</details>
<details name="faq">
<summary>Does it work offline?</summary>
Yes.
</details>Preview (click it)
What does it cost?
Nothing.
Does it work offline?
Yes.
user-content- prefix added to the value. Every block in the group gets the same prefix, so the grouping still works. PyPI strips name along with open, and older browsers ignore it and let every section open independently, which is a harmless fallback.What You Can Put Inside
Once the blank line has ended the HTML block, the content is ordinary Markdown. Headings, lists, tables, images, links, and fenced code blocks with syntax highlighting all behave exactly as they do outside the section.
Markdown
<details>
<summary>Everything works in here</summary>
### A heading
A paragraph, a list, and a table:
- one
- two
| Column | Value |
| ------ | ----- |
| rows | fine |
</details>Preview (click it)
Everything works in here
A heading
A paragraph, a list, and a table:
- one
- two
| Column | Value |
|---|---|
| rows | fine |
Markdown
<details>
<summary>Show the install command</summary>
```bash
npm install my-package
```
</details>Preview (click it)
Show the install command
npm install my-package
> [!NOTE]-style alerts nested inside other elements, so inside a <details> block you get a plain blockquote with [!NOTE] printed as text. Put the alert outside the toggle.Nesting Collapsible Sections
A <details> block can contain another one, as deep as you need. Each level needs its own blank lines around its body — the rule is per-block, not per-document. The usual shape is one outer toggle for a topic and an inner one per platform or per version.
Markdown
<details>
<summary>Platform notes</summary>
<details>
<summary>macOS</summary>
Requires Xcode command line tools.
</details>
<details>
<summary>Windows</summary>
Requires the Visual C++ build tools.
</details>
</details>Preview (click it)
Platform notes
macOS
Requires Xcode command line tools.
Windows
Requires the Visual C++ build tools.
Formatting the Summary Label
The <summary> line sits before the blank line, so it is still raw HTML — which means Markdown written inside it is not parsed. This surprises people who expect **Bold** to work there.
Markdown
<details>
<summary>**Bold summary**</summary>
Body text.
</details>Preview (click it)
**Bold summary**
Body text.
Markdown
<details>
<summary><b>Bold summary</b> with <code>code</code></summary>
Body text.
</details>Preview (click it)
Bold summary with code
Body text.
If you want a real Markdown heading as the label, the same blank-line rule that saved the body will save the summary: open the tag, leave a blank line, write the Markdown, leave another blank line, and close the tag. The blank line ends the HTML block long enough for the parser to process what is between.
Markdown
<details>
<summary>
### A heading as the label
</summary>
Body text.
</details>Preview (click it)
A heading as the label
Body text.
MDX is the exception: there, <summary>**Bold**</summary> on one line does render as bold, because MDX parses inline Markdown inside JSX tags.
Collapsible Sections Inside a List
Numbered setup instructions with an optional troubleshooting toggle per step is one of the most useful shapes there is, and it is where the indentation trap bites. Indent the block to the list item's content column — two spaces under a bullet, three under a 1. — and never four, which turns the whole thing into a code block.
Markdown
1. Install the dependencies.
<details>
<summary>Troubleshooting</summary>
Delete `node_modules` and try again.
</details>
2. Run the build.Preview (click it)
Install the dependencies.
Troubleshooting
Delete
node_modulesand try again.Run the build.
Native Alternatives
<details> is the answer on GitHub and GitLab because those are HTML-rendering surfaces. Several other tools grew their own collapsible syntax, and where one exists it is almost always the better choice — it is styled, it nests cleanly, and it does not depend on HTML being allowed.
Obsidian: foldable callouts
Add a - after the callout type to start it collapsed, or a + to start it expanded. Markdown, wikilinks, embeds, and nested callouts all work inside. That matters more in Obsidian than anywhere else: Obsidian never parses Markdown inside HTML, so a <details> body there can only hold plain text or HTML, with no blank lines.
> [!note]- Are callouts foldable?
> Yes. A minus sign collapses the callout by default.
> [!tip]+ This one starts open
> A plus sign expands it by default.Material for MkDocs: ??? admonitions
Start an admonition with ??? instead of !!! and it renders as an expandable block. Requires the pymdownx.details extension in mkdocs.yml.
??? note "Collapsed by default"
Requires the pymdownx.details extension.
???+ note "Expanded by default"
The plus sign starts it open.Hugo: the details shortcode
Hugo drops raw HTML unless you set markup.goldmark.renderer.unsafe = true, so a hand-written <details> block vanishes by default. Since v0.140.0 Hugo ships a built-in shortcode that emits the element for you, with summary, open, and name arguments.
{{< details summary="Show the install command" >}}
Run `npm install my-package`.
{{< /details >}}Notion: toggle blocks
Notion drops pasted HTML, so <details> does nothing there. Its equivalent is a toggle block: type > followed by a space, or use /toggle. Note that this is the same keystroke that makes a blockquote in standard Markdown — in Notion a quote is " plus a space.
Chat apps: spoilers, and that is all
Discord, Slack, and Reddit allow no HTML in messages, so there is no collapsible section on any of them. The nearest thing is a spoiler, which hides a run of inline text behind a click but carries no label and no block content. Slack has no equivalent at all.
Discord: Here is the answer: ||the butler did it||
Reddit: Here is the answer: >!the butler did it!<Common Mistakes
Four of these five are about where the blank lines and the indentation go. None of them produces an error message — the section just renders wrong, or swallows your document.
Broken
<details>
<summary>Notes</summary>
This is **bold**.
</details>Fixed
<details>
<summary>Notes</summary>
This is **bold**.
</details>Broken
- Step one
<details>
<summary>More</summary>
Hidden text.
</details>Fixed
- Step one
<details>
<summary>More</summary>
Hidden text.
</details>Broken
<details>
<summary>**Bold label**</summary>
Body.
</details>Fixed
<details>
<summary><b>Bold label</b></summary>
Body.
</details>Broken
<details>
<summary>Notes</summary>
Hidden text.
## The rest of your documentFixed
<details>
<summary>Notes</summary>
Hidden text.
</details>
## The rest of your documentBroken
<details open>
<summary>Read me first</summary>
Important setup notes.
</details>Fixed
<details>
<summary>Read me first</summary>
Important setup notes.
</details>Quick Reference
| Syntax | Where it applies | Starts |
|---|---|---|
| <details>...</details> | Anywhere raw HTML is allowed - GitHub, GitLab, MDX, VS Code | Closed |
| <details open> | Same, minus PyPI, which strips the attribute | Open |
| <details name="x"> | Accordion group: one open at a time | Closed |
| <summary>Label</summary> | The clickable label; inline HTML only (Markdown works in MDX) | — |
| > [!note]- Title | Obsidian foldable callout | Closed |
| > [!note]+ Title | Obsidian foldable callout | Open |
| ??? note "Title" | MkDocs with pymdownx.details | Closed |
| {{< details summary="..." >}} | Hugo 0.140+ built-in shortcode | Closed |
| ???+ note "Title" | MkDocs with pymdownx.details | Open |
| > + space | Notion toggle block (not a blockquote) | Closed |
| ||spoiler|| | Discord - inline text only, no label | Hidden |
| >!spoiler!< | Reddit - inline text only, no label | Hidden |
Platform Support
Support tracks one thing: whether the renderer allows raw HTML through. Document and repository platforms do. Chat apps do not, which is why there is no collapsible section in a Discord or Slack message and no workaround that produces one.
| Platform | Supported? | Notes |
|---|---|---|
| GitHub | Yes | READMEs, issues, PRs, discussions, wikis, and gists. <details>, <summary>, open, and name all survive the sanitizer. Alerts (> [!NOTE]) do not render inside one. |
| GitLab | Yes | Same syntax and blank-line rule. GitLab's own docs example also uses the blank-line form inside <summary>. |
| CommonMark / GFM | Yes | Not a Markdown feature at all - it is raw HTML passthrough, which the spec allows. Any parser with HTML enabled renders it. |
| MDX (Docusaurus, Next.js, Astro) | Yes | <details> is valid JSX. Keep the blank line after </summary>: without it MDX wraps the label and body in one <p> and the label breaks. Unlike GitHub, **bold** inside <summary> is parsed. Docusaurus styles it automatically. |
| Obsidian | Partial | HTML <details> renders, but Obsidian never parses Markdown inside HTML and a blank line ends the HTML block, so the body must be plain text or HTML. Foldable callouts - > [!note]- - are the better fit. |
| VS Code preview | Yes | The built-in preview allows HTML, so the disclosure widget works as it does in a browser. |
| MkDocs / Material | Partial | Raw HTML works. The idiomatic form is a ??? collapsible admonition, which needs the pymdownx.details extension. |
| PyPI | Partial | readme_renderer allows <details> and <summary>, but its allow-list has no open attribute, so the section always ships collapsed. |
| Jupyter / R Markdown | Yes | HTML passes through to the rendered notebook and to knitted HTML output. |
| Hugo | Partial | Raw HTML is dropped by default (unsafe = false). Use the built-in {{< details >}} shortcode (Hugo 0.140+) or enable unsafe. |
| Notion | Partial | Pasted HTML is not honored. Notion's native equivalent is a toggle block: type > then a space. |
| No | Reddit does not render HTML, so the tags print as literal text. Use a spoiler, >!like this!<, to hide a line. | |
| Discord / Slack | No | No HTML at all. Discord has ||spoilers||; Slack has nothing that hides text. |
Frequently Asked Questions
How do you make a collapsible section in Markdown?
Markdown has no collapsible syntax, so you use the HTML <details> element, which every major Markdown renderer passes through. Put a <summary> tag on the line after <details> to hold the clickable label, leave a blank line, write your Markdown, leave another blank line, and close with </details>. The blank lines are what allow the content inside to be parsed as Markdown rather than printed as raw text.
Why is my collapsible section showing **asterisks** instead of bold text?
There is no blank line after the closing </summary> tag. In CommonMark an HTML block continues until the first blank line, so everything pressed up against <summary> is still inside the raw HTML and is emitted verbatim. Adding one empty line after </summary> fixes it. A blank line before </details> is optional in CommonMark and on GitHub, but harmless.
How do I make a collapsible section expanded by default?
Add the open attribute to the opening tag: <details open>. The reader can still collapse it. Note that open is not guaranteed everywhere - PyPI's README sanitizer allows the <details> tag but strips the attribute, so a section you meant to ship expanded arrives collapsed there.
Can I put code blocks, tables, and images inside a collapsible section?
Yes. Once the blank line after </summary> has ended the HTML block, the content inside is ordinary Markdown - fenced code blocks with syntax highlighting, pipe tables, images, lists, headings, and even other collapsible sections all work. This is the usual way to keep a long install log or a screenshot gallery out of the way in a README.
Can you nest collapsible sections in Markdown?
Yes. A <details> block inside another <details> block nests as deeply as you like, and each level needs its own blank line after its </summary>. Nesting is common for platform-specific instructions: one outer toggle for Installation, and an inner one per operating system.
How do I make a Markdown accordion where only one section is open at a time?
Give every <details> in the group the same name attribute: <details name="faq">. Opening one closes the others, with no JavaScript. Current versions of Chrome, Edge, Firefox, and Safari support it, and GitHub keeps the attribute (it prefixes the value with user-content-, which still groups them). Older browsers ignore it and let several open at once, and PyPI strips it.
How do I make the summary label bold or add a heading to it?
Markdown written inside <summary> on the same line is not parsed, because that line is still part of the raw HTML block. Use inline HTML instead - <summary><b>Bold label</b></summary>. If you need a real heading, put a blank line after the opening <summary> tag, write the Markdown, then a blank line before </summary>, which ends the HTML block long enough for the parser to see it.
Does a collapsible section work in a list item?
Yes, as long as you indent it to the list item's content column - two spaces under a bullet, three under a numbered item - and keep the blank lines. Four spaces is the trap: that is an indented code block, so the tags render as literal code instead of a toggle.
Does GitHub support collapsible sections?
Yes, everywhere GitHub renders Markdown: READMEs, issues, pull requests, discussions, wikis, and gists. GitHub's HTML sanitizer allows <details>, <summary>, and the open and name attributes. This is the single most common place people use them, usually to collapse long logs, changelogs, or optional setup steps.
Do collapsible sections work on Reddit, Discord, or Slack?
No. None of the three allow raw HTML in messages. Reddit escapes the tags so they show up as literal text; Discord and Slack simply have no equivalent element. The closest thing is a spoiler - ||text|| on Discord, >!text!< on Reddit - which hides a run of text behind a click but has no label and no block content.
What is the Obsidian equivalent of a collapsible section?
A foldable callout. Add a minus sign after the callout type to start it collapsed - > [!note]- Title - or a plus sign to start it expanded. Unlike raw HTML, foldable callouts are styled, nestable, and support Markdown, wikilinks, and embeds inside them. HTML <details> also renders in Obsidian, but Obsidian does not parse Markdown inside HTML and a blank line ends the block, so only plain text or HTML works in the body.
What about Notion, MkDocs, and Docusaurus?
Notion ignores pasted HTML and uses its own toggle block: type > followed by a space. Material for MkDocs has collapsible admonitions - ??? note for collapsed, ???+ note for expanded - which need the pymdownx.details extension enabled. Docusaurus renders plain <details> and styles it automatically, since MDX treats it as a JSX element. Hugo drops raw HTML by default, so use its built-in details shortcode: {{< details summary="Label" >}}...{{< /details >}}.
Is content inside a collapsed section still searchable and indexed?
Yes. A collapsed <details> block is present in the HTML, so search engine crawlers and GitHub's code search see it - it is hidden visually, not removed. Chrome's find-in-page also searches inside closed sections and opens them on a match, though not every browser does. Do not use a collapsible section to hide anything sensitive, and do not assume readers will click: if something must be read, leave it in the open.