Summary
NcRichText renders user-generated markdown across Nextcloud apps (e.g. Talk). Spoilers are a nice addition in chat/comment contexts.
RFC to add support for inline spoilers in NcRichText using the Discord-style and Telegram-style syntax. Spoiler content renders hidden behind a bar and is revealed on click - before that .
Discord (p.s. images are out of scope of this RFC)

Telegram

Syntax
Markdown has no standard spoiler syntax (see commonmark/commonmark-spec/issues/570)
Suggested convention: ||…|| (double pipes, inline).
This is a ||hidden|| word.
Behavior
- Gating: extended markdown only (useExtendedMarkdown) — spoilers are an extension, alongside GFM.
- Reveal: click to reveal. State is per-instance and one-way (once revealed, stays revealed).
- Accessibility: to be discussed - if revealed on click, maybe pass to readers as-is, or wrap with "spoiler alert" - keyboard a11y should be respected + aria-expanded + descriptive aria-label.
Proposed implementation
Follows the existing custom-plugin pattern in emarkAutolink, remarkPlaceholder,remarkUnescape, remarkStripCode).
- remarkSpoiler.ts — remark transformer that visits text nodes, splits on ||…|| (handles multiple matches per node), and emits a dedicated spoiler element node carrying the inner text.
- Pipeline registration in NcRichText.vue → renderMarkdown(), gated on useExtendedMarkdown, placed after remarkGfm (verified: GFM leaves ||…|| untouched in normal text, so ordering is safe — see Limitations for the table exception).
- NcTextSpoiler.vue — small <script setup> component (sibling of NcRichTextExternalLink.vue) wrapping a with internal revealed ref; hidden state styled via CSS module. (animated or not?)
- createElement mapping in NcRichText.vue — branch rendering the spoiler node to NcRichTextSpoiler.
- unit tests in remarkSpoiler.spec.js, mirroring autoLink.spec.js, playwrigth tests with kbd a11y and clicks
To discuss - if we make it client-side only, or with server involvement (pass spoiler text with richObjectParameters)
Limitations (v1)
- No nested inline formatting inside a spoiler: ||bold|| renders the ** literally. Formatting around a spoiler (||x||) works. This matches the library's behavior too; full nesting would require a micromark syntax extension. Should be documented.
- No spoilers inside GFM table cells: GFM's table tokenizer consumes | as cell delimiters before any transformer runs. Matches Discord/GFM behavior — escape as | in tables. Should be documented.
Alternative: existing library
remark-inline-spoiler implements exactly this syntax via a proper micromark tokenizer (micromark-extension-inline-spoiler + mdast-util-inline-spoiler), but:
- it is new and has small amount of downloads (although maintained)
- it also does not support nested markdown
- it adds a 3-package dependency tree, where we can do it with a small helper as we already have
Summary
NcRichText renders user-generated markdown across Nextcloud apps (e.g. Talk). Spoilers are a nice addition in chat/comment contexts.
RFC to add support for inline spoilers in NcRichText using the Discord-style and Telegram-style syntax. Spoiler content renders hidden behind a bar and is revealed on click - before that .
Discord (p.s. images are out of scope of this RFC)

Telegram

Syntax
Markdown has no standard spoiler syntax (see
commonmark/commonmark-spec/issues/570)Suggested convention: ||…|| (double pipes, inline).
Behavior
Proposed implementation
Follows the existing custom-plugin pattern in emarkAutolink, remarkPlaceholder,remarkUnescape, remarkStripCode).
To discuss - if we make it client-side only, or with server involvement (pass spoiler text with richObjectParameters)
Limitations (v1)
Alternative: existing library
remark-inline-spoilerimplements exactly this syntax via a proper micromark tokenizer (micromark-extension-inline-spoiler + mdast-util-inline-spoiler), but: