# Spoiler
A **built-in** tag that hides long content behind a **show-more** toggle. When the block body
is taller than `maxHeight`, a toggle appears and the reader expands the rest on demand; the
body renders as ordinary Markdown. Use it as `{% spoiler %}` in Markdown,
or call it from Python logic (loops, snippets) via `component('aardvark', 'spoiler', …)`.
## Demonstrations
A bare spoiler collapses its body once the content is taller than `maxHeight` (60px here), and
the **Show more** toggle reveals the rest:
This region starts collapsed once its content is taller than `maxHeight`.
A **Show more** toggle reveals the rest, and **Hide** collapses it again.
The body is ordinary Markdown — **bold**, `code`, [links](/), and lists all work.
- It is good for long change notes, FAQs, and footnote-y asides.
- The toggle only appears when the content actually overflows `maxHeight`.
Source: Markdown
```aardvark
{% spoiler maxHeight=60 %}
This region starts collapsed once its content is taller than `maxHeight`.
A **Show more** toggle reveals the rest, and **Hide** collapses it again.
The body is ordinary Markdown — **bold**, `code`, [links](/), and lists all work.
- It is good for long change notes, FAQs, and footnote-y asides.
- The toggle only appears when the content actually overflows `maxHeight`.
{% endSpoiler %}
```
Source: Python
```python
component('aardvark', 'spoiler', maxHeight=60, children=(
"This region starts collapsed once its content is taller than `maxHeight`.\n"
"A **Show more** toggle reveals the rest, and **Hide** collapses it again.\n\n"
"- It is good for long change notes, FAQs, and footnote-y asides.\n"
"- The toggle only appears when the content actually overflows `maxHeight`.\n"
))
```
### Custom labels
`showLabel` and `hideLabel` set the toggle text for the collapsed and expanded states:
The toggle text is yours to set. Keep `showLabel` short — it sits inline under the
collapsed content. This body is long enough to overflow the 40px `maxHeight`, so the
toggle shows.
Source: Markdown
```aardvark
{% spoiler maxHeight=40 showLabel='Read the details' hideLabel='Collapse' %}
The toggle text is yours to set. Keep `showLabel` short — it sits inline under the
collapsed content. This body is long enough to overflow the 40px `maxHeight`, so the
toggle shows.
{% endSpoiler %}
```
Source: Python
```python
component('aardvark', 'spoiler', maxHeight=40,
showLabel='Read the details', hideLabel='Collapse',
children='The toggle text is yours to set…')
```
### Instant reveal
`transitionDuration=0` disables the reveal animation, so the body appears immediately:
With `transitionDuration=0` the content snaps open and shut with no slide. Useful when you
want the toggle behavior without any motion. This paragraph is tall enough to overflow the
40px `maxHeight`, so the toggle appears.
Source: Markdown
```aardvark
{% spoiler maxHeight=40 transitionDuration=0 %}
With `transitionDuration=0` the content snaps open and shut with no slide. Useful when you
want the toggle behavior without any motion. This paragraph is tall enough to overflow the
40px `maxHeight`, so the toggle appears.
{% endSpoiler %}
```
Source: Python
```python
component('aardvark', 'spoiler', maxHeight=40, transitionDuration=0,
children='With transitionDuration=0 the content snaps open…')
```
## With other components
A spoiler body is full Markdown, so it can hold any other component — here a {% card %}
and a {% badge %} stay hidden until the reader expands the region:
Recent updates New
A major release with breaking changes and a migration guide.
Source: Markdown
```aardvark
{% spoiler maxHeight=50 showLabel='Show the changelog' hideLabel='Hide' %}
Recent updates {% badge color='green' %}New{% endBadge %}
{% card title="v2.0" %}
A major release with breaking changes and a migration guide.
{% endCard %}
{% endSpoiler %}
```
Source: Python
```python
body = "Recent updates " + component('aardvark', 'badge', color='green', children='New')
body += "\n\n" + component('aardvark', 'card', title='v2.0',
children='A major release with breaking changes and a migration guide.')
page.print(component('aardvark', 'spoiler', maxHeight=50,
showLabel='Show the changelog', hideLabel='Hide', children=body))
```
## Attributes
| Attribute | Valid values | Description |
| --- | --- | --- |
| (body) | Markdown | The collapsible content. Rendered as Markdown. Close the tag with `{% endSpoiler %}`. |
| `maxHeight` | integer (pixels) | Visible height before the toggle appears. Defaults to `100`. The toggle only shows when the body is taller than this. |
| `showLabel` | string | Toggle text while collapsed. Defaults to `Show more`. |
| `hideLabel` | string | Toggle text while expanded. Defaults to `Hide`. |
| `transitionDuration` | integer (ms) | Reveal animation duration. Defaults to `200`; set `0` to disable the animation. |
## CSS Selectors
Target the rendered element through its island marker — `[data-aardvark-island="Spoiler"]` — or through the Mantine Styles API classes (`.mantine-Spoiler-root` and its inner parts):
```css
/* Every rendered Spoiler carries this island marker */
[data-aardvark-island="Spoiler"] { }
/* Mantine Styles API class on the root element */
.mantine-Spoiler-root { }
.mantine-Spoiler-content { }
```
## Injecting Attributes
`attr={…}` forwards raw HTML attributes — including event handlers — straight onto the rendered element, so you can wire DOM behavior the tag does not expose. The handler can be a full multi-line script, not just one expression — this one logs the value to the console and shows it in an alert:
A paragraph long enough to be collapsed behind the Show more toggle, then revealed on click.
Source: Markdown
```aardvark
{% spoiler maxHeight=60 attr={'onclick': '''
const value = this.innerText;
console.log('attr demo value:', value);
alert(value);
'''} %}
A paragraph long enough to be collapsed behind the Show more toggle, then revealed on click.
{% endSpoiler %}
```
Source: Python
```python
component('aardvark', 'spoiler', maxHeight=60,
children='A paragraph long enough to be collapsed behind the Show more toggle, then revealed on click.',
attr={'onclick': '''
const value = this.innerText;
console.log('attr demo value:', value);
alert(value);
'''})
```