
# Spoiler Spans

With the flag `MD_FLAG_SPOILERS`, MD4C enables recognition of inline spoiler
spans using the `||text||` syntax (popularized by Telegram and Discord).

A spoiler span is content wrapped in exactly two consecutive pipe characters
(`||`) on each side.  The content is intended to be hidden by default and
revealed on user interaction (tap, hover, click, etc.).  Rendering of the
hidden state is the application's responsibility; the HTML renderer wraps the
content in `<x-spoiler>` tags.


## Basic recognition

```````````````````````````````` example
||Hello, world!||
.
<p><x-spoiler>Hello, world!</x-spoiler></p>
.
--fspoilers
````````````````````````````````

Spoilers may appear inline alongside normal text:

```````````````````````````````` example
This is normal text with ||hidden content|| revealed here.
.
<p>This is normal text with <x-spoiler>hidden content</x-spoiler> revealed here.</p>
.
--fspoilers
````````````````````````````````

Multiple independent spoiler spans in the same paragraph:

```````````````````````````````` example
||first|| and ||second||
.
<p><x-spoiler>first</x-spoiler> and <x-spoiler>second</x-spoiler></p>
.
--fspoilers
````````````````````````````````

A spoiler span at the very start and end of a paragraph:

```````````````````````````````` example
||entire paragraph is a spoiler||
.
<p><x-spoiler>entire paragraph is a spoiler</x-spoiler></p>
.
--fspoilers
````````````````````````````````


## Flag required

Without `MD_FLAG_SPOILERS` the `||` sequence is treated as literal text:

```````````````````````````````` example
||hidden||
.
<p>||hidden||</p>
.
````````````````````````````````


## Nested inline spans inside a spoiler

Emphasis inside a spoiler:

```````````````````````````````` example
||nested *emphasis*||
.
<p><x-spoiler>nested <em>emphasis</em></x-spoiler></p>
.
--fspoilers
````````````````````````````````

Strong emphasis inside a spoiler:

```````````````````````````````` example
||**bold** and _italic_ together||
.
<p><x-spoiler><strong>bold</strong> and <em>italic</em> together</x-spoiler></p>
.
--fspoilers
````````````````````````````````

Inline code inside a spoiler:

```````````````````````````````` example
||spoiler with `code`||
.
<p><x-spoiler>spoiler with <code>code</code></x-spoiler></p>
.
--fspoilers
````````````````````````````````

A link inside a spoiler:

```````````````````````````````` example
||spoiler with [a link](http://example.com)||
.
<p><x-spoiler>spoiler with <a href="http://example.com">a link</a></x-spoiler></p>
.
--fspoilers
````````````````````````````````

Strikethrough inside a spoiler (requires both flags):

```````````````````````````````` example
||~~strikethrough inside spoiler~~||
.
<p><x-spoiler><del>strikethrough inside spoiler</del></x-spoiler></p>
.
--fspoilers --fstrikethrough
````````````````````````````````

A spoiler inside strikethrough:

```````````````````````````````` example
~~del with ||spoiler|| inside~~
.
<p><del>del with <x-spoiler>spoiler</x-spoiler> inside</del></p>
.
--fspoilers --fstrikethrough
````````````````````````````````


## Suppression inside code spans and code blocks

Pipe characters inside a code span are not recognized as spoiler delimiters:

```````````````````````````````` example
`code with ||pipes||`
.
<p><code>code with ||pipes||</code></p>
.
--fspoilers
````````````````````````````````

Similarly inside a fenced code block:

```````````````````````````````` example
```
||not a spoiler||
```
.
<pre><code>||not a spoiler||
</code></pre>
.
--fspoilers
````````````````````````````````

And inside an indented code block:

```````````````````````````````` example
    ||not a spoiler||
.
<pre><code>||not a spoiler||
</code></pre>
.
--fspoilers
````````````````````````````````


## Unmatched delimiters

A lone `||` with no matching closer is left as literal text:

```````````````````````````````` example
||unclosed spoiler
.
<p>||unclosed spoiler</p>
.
--fspoilers
````````````````````````````````

A lone closer with no preceding opener is also left as literal text:

```````````````````````````````` example
unclosed spoiler||
.
<p>unclosed spoiler||</p>
.
--fspoilers
````````````````````````````````


## Backslash escaping

A backslash before the first pipe escapes it, breaking the `||` pair and
preventing spoiler recognition:

```````````````````````````````` example
\||not a spoiler||
.
<p>||not a spoiler||</p>
.
--fspoilers
````````````````````````````````


## Paragraph boundary

A spoiler cannot span a paragraph break (same rule as emphasis):

```````````````````````````````` example
||starts here

ends here||
.
<p>||starts here</p>
<p>ends here||</p>
.
--fspoilers
````````````````````````````````


## Soft line break inside a spoiler

A soft line break within the same block is permitted:

```````````````````````````````` example
||multi
line spoiler||
.
<p><x-spoiler>multi
line spoiler</x-spoiler></p>
.
--fspoilers
````````````````````````````````


## Empty spoiler

Only `||` (spans of length 2) are recognzied as spoiler marks:

```````````````````````````````` example
||||
.
<p>||||</p>
.
--fspoilers
````````````````````````````````

But escaped `|` does not count:

```````````````````````````````` example
||\|||
.
<p><x-spoiler>|</x-spoiler></p>
.
--fspoilers
````````````````````````````````


## Block-level contexts

### ATX headings

```````````````````````````````` example
# ||heading spoiler||
.
<h1><x-spoiler>heading spoiler</x-spoiler></h1>
.
--fspoilers
````````````````````````````````

```````````````````````````````` example
## ||level two||
.
<h2><x-spoiler>level two</x-spoiler></h2>
.
--fspoilers
````````````````````````````````

### Block quotes

```````````````````````````````` example
> ||hidden in a quote||
.
<blockquote>
<p><x-spoiler>hidden in a quote</x-spoiler></p>
</blockquote>
.
--fspoilers
````````````````````````````````

Nested block quotes:

```````````````````````````````` example
> > ||nested quote spoiler||
.
<blockquote>
<blockquote>
<p><x-spoiler>nested quote spoiler</x-spoiler></p>
</blockquote>
</blockquote>
.
--fspoilers
````````````````````````````````

### Unordered lists

```````````````````````````````` example
- ||list item spoiler||
- normal item
.
<ul>
<li><x-spoiler>list item spoiler</x-spoiler></li>
<li>normal item</li>
</ul>
.
--fspoilers
````````````````````````````````

### Ordered lists

```````````````````````````````` example
1. ||first item||
2. normal item
.
<ol>
<li><x-spoiler>first item</x-spoiler></li>
<li>normal item</li>
</ol>
.
--fspoilers
````````````````````````````````

### Task lists (requires `MD_FLAG_TASKLISTS`)

```````````````````````````````` example
- [ ] ||task item spoiler||
- [x] done
.
<ul>
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled><x-spoiler>task item spoiler</x-spoiler></li>
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled checked>done</li>
</ul>
.
--fspoilers --ftasklists
````````````````````````````````

### Tables (requires `MD_FLAG_TABLES`)

> [!WARNING] Consider this experimental feature for now, which can possibly
> be removed as it creates incompatibility with Github Flavored Markdown (GFM)
> tables.
>
> GFM does not support spoilers at all, and double `||` inside a table means
> an empty cell (or even longer spans, e.g. `|||||`, mean multiple empty cells).
>
> If this proves to be too problematic, we might disallow spoilers in a table
> in future MD4C versions.

A spoiler inside a table cell:

```````````````````````````````` example
| A | B |
|---|---|
| ||spoiler|| | baz |
.
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
</tr>
</thead>
<tbody>
<tr>
<td><x-spoiler>spoiler</x-spoiler></td>
<td>baz</td>
</tr>
</tbody>
</table>
.
--fspoilers --ftables
````````````````````````````````

Without the spoiler extension enabled, the GFM-compatible table behavior is
retained:

```````````````````````````````` example
| A | B | C | D | E |
|---|---|---|---|---|
| a     ||c||     e |
.
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
</tr>
</thead>
<tbody>
<tr>
<td>a</td>
<td></td>
<td>c</td>
<td></td>
<td>e</td>
</tr>
</tbody>
</table>
.
--ftables
````````````````````````````````

## Interaction with other extensions

### Wiki-links (requires `MD_FLAG_WIKILINKS`)

It's possible to use spoilers inside the wiki-link label:

```````````````````````````````` example
[[target|display with ||spoiler||]]
.
<p><x-wikilink data-target="target">display with <x-spoiler>spoiler</x-spoiler></x-wikilink></p>
.
--fspoilers --fwiki-links
````````````````````````````````

A wiki-link extension may use only single '|' as the optional delimiter between
the destination and the label so the first `||` is ignored for the purpose:

```````````````````````````````` example
[[a||b|label with ||spoiler||]]
.
<p><x-wikilink data-target="a||b">label with <x-spoiler>spoiler</x-spoiler></x-wikilink></p>
.
--fspoilers --fwiki-links
````````````````````````````````
To avoid ambiguity, it's not possible to chain the wiki-link delimiter and
spoiler marks, so this does not form correct spoiler inside a wiki-link but
a wiki-link without explicit label (i.e. where all contents between `[[` and
`]]` forms both the destination and the label:

```````````````````````````````` example
[[dest|||spoiler||]]
.
<p><x-wikilink data-target="dest|||spoiler||">dest|||spoiler||</x-wikilink></p>
.
--fspoilers --fwiki-links
````````````````````````````````

Links, images, and inline spans inside spoiler spans are recognized normally:

```````````````````````````````` example
||[link](http://example.com) inside spoiler||
.
<p><x-spoiler><a href="http://example.com">link</a> inside spoiler</x-spoiler></p>
.
--fspoilers
````````````````````````````````

```````````````````````````````` example
||![img](http://example.com/img.png) inside spoiler||
.
<p><x-spoiler><img src="http://example.com/img.png" alt="img"> inside spoiler</x-spoiler></p>
.
--fspoilers
````````````````````````````````

```````````````````````````````` example
||*em* inside spoiler||
.
<p><x-spoiler><em>em</em> inside spoiler</x-spoiler></p>
.
--fspoilers
````````````````````````````````

Wiki links with a `|` separator must not be mistaken for spoiler delimiters:

```````````````````````````````` example
[[foo|bar]]
.
<p><x-wikilink data-target="foo">bar</x-wikilink></p>
.
--fspoilers --fwiki-links
````````````````````````````````

A wiki link whose label contains an unrelated `|` character:

```````````````````````````````` example
[[foo|bar|baz]]
.
<p><x-wikilink data-target="foo">bar|baz</x-wikilink></p>
.
--fspoilers --fwiki-links
````````````````````````````````
