npm.io
0.1.1 • Published yesterday

@mirrordown/mdit-spoiler

Licence
MIT
Version
0.1.1
Deps
0
Size
33 kB
Vulns
0
Weekly
0
Stars
2

@mirrordown/mdit-spoiler

Part of Mirrordown — a suite of markdown syntax extensions for the unified and markdown-it ecosystems.

A markdown-it plugin for the spoiler syntax extension.

Overview

The spoiler plugin hides content behind a click-to-reveal cover using Discord's ||…|| syntax. Wrap inline content in double pipes — ||the butler did it|| — and it renders as an obscured bar; click it (or focus it and press Space) to reveal the text in place. Wrap an image and it renders blurred with a centered SPOILER label, like Discord's image spoilers.

The entire interaction is built from HTML and CSS only — a <label> wrapping a visually-hidden checkbox and the content, revealed with the :checked sibling selector. No JavaScript runs, so it works in environments that disable scripts, such as the VSCode Markdown preview.

<label class="markdown-spoiler">
  <input type="checkbox" class="markdown-spoiler-toggle" aria-label="spoiler" />
  <span class="markdown-spoiler-content">the butler did it</span>
</label>

The checkbox is the only interactive control, so it stays keyboard-operable and is announced by screen readers as a spoiler control — the hidden text is not read aloud until the reader chooses to reveal it.

Syntax

Wrap any inline content in ||…||. Click a bar below to reveal it; click again to hide it.

The killer was ||the butler|| all along, hidden in ||the conservatory||.

In renderers without the plugin, ||…|| renders as plain text.

Rich inline content

A spoiler can wrap any inline markup — emphasis, code, links — and it stays obscured until revealed. A long spoiler wraps across lines with each line getting its own bar, just like Discord.

The recipe needs ||**two** cups of `flour` and a
[secret ingredient](https://example.com) that nobody expects||.
Image spoilers

Wrap an image to hide it behind a blur and a SPOILER label — Discord's treatment for spoilered image embeds. Clicking reveals the sharp image.

Careful, dinner photo incoming: ||![A young sapling](./assets/sapling.jpg "Sapling")||
Spoilered, zoomable images

Combine with the lightbox plugin (||!![…]()||) for a spoilered image that is also click-to-zoom once revealed.

The reveal: ||!![Mount Fuji at dawn](./assets/fuji.jpg "Mount Fuji")||

A spoiler works inside a link — the whole revealed content remains the link target.

Read [the ||shocking twist||](https://example.com) at your own risk.

Accessibility

The spoiler is a real checkbox with aria-label="spoiler", so assistive technology announces it as a control the user can operate rather than reading the hidden text aloud. Keyboard users Tab to the spoiler and press Space to reveal it; a focus ring marks the current spoiler. Revealing is reversible (unlike Discord, which locks open) — a superset of the expected behavior.

Customization

The stylesheet keeps its rules in @layer markdown-spoiler, so any unlayered CSS you write overrides them without !important. The common knobs are exposed as custom properties — set them on :root or any ancestor:

Property Default Description
--markdown-spoiler-bar #202225 Obscured bar color (text spoilers).
--markdown-spoiler-radius 0.25rem Bar corner radius.
--markdown-spoiler-duration 0.15s Reveal transition duration.
--markdown-spoiler-revealed color-mix(in srgb, currentColor 8%, …) Background behind revealed text.
--markdown-spoiler-media-blur 2.5rem Blur radius for image spoilers.
--markdown-spoiler-label "SPOILER" Text of the image-spoiler pill.
:root {
  --markdown-spoiler-bar: #111;
  --markdown-spoiler-radius: 0.5rem;
  --markdown-spoiler-label: "HIDDEN";
}

Browser support

Text spoilers work everywhere (checkbox + sibling selector). Image spoilers use :has() to detect media and box-decoration-break for per-line bars (Chromium 105+, Safari, Firefox 122+); where unsupported, an image spoiler still hides its content, just without the per-line polish.

Install

npm install @mirrordown/mdit-spoiler
Standalone
import MarkdownIt from "markdown-it";
import { spoiler } from "@mirrordown/mdit-spoiler";
import "@mirrordown/mdit-spoiler/styles";

const md = new MarkdownIt().use(spoiler);
VitePress
// .vitepress/config.ts
import { defineConfig } from "vitepress";
import { spoiler } from "@mirrordown/mdit-spoiler";
import "@mirrordown/mdit-spoiler/styles";

export default defineConfig({
  markdown: {
    config: (md) => md.use(spoiler)
  }
});

Documentation

Full documentation, more examples, and configuration options: github.com/mirrordown/mirrordown (dedicated docs site coming soon).

License

MIT Drake Costa