@mirrordown/remd-lightbox
v0.1.0
Published
A rehype plugin to opt an image into a JavaScript-free <dialog> lightbox with a leading !! (zoom on click).
Readme
@mirrordown/remd-lightbox
Part of Mirrordown — a suite of markdown syntax extensions for the unified and markdown-it ecosystems.
A rehype plugin that opts an image into a click-to-zoom lightbox — with no JavaScript.
Overview
Opt an image in with a leading !!:
!The marked image becomes a trigger that opens the full-size image in a modal <dialog>, dimming and blurring the page behind it. Unmarked images (![…]) render normally. The entire interaction — open, close, backdrop dismiss, Esc, and the zoom/fade animation — is built from modern declarative HTML and CSS only: <dialog>, the Invoker Commands API (command/commandfor), closedby="any", and @starting-style. That makes it work in environments that disable scripts, such as the VSCode Markdown preview.
Click the image to zoom; click it again, click the backdrop, or press Esc to close. In renderers without the plugin, the extra ! renders as plain text and the image still shows.
Install
npm install @mirrordown/remd-lightboxUsage
It operates on the hast tree, so it runs after remark-rehype.
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import rehypeStringify from "rehype-stringify";
import { rehypeLightbox } from "@mirrordown/remd-lightbox";
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeLightbox)
.use(rehypeStringify);
processor.processSync('!');The plugin wraps each opted-in image in an inline trigger button and appends the
matching <dialog> elements at the end of the document. Import the stylesheet
(@mirrordown/remd-lightbox/lightbox.css) for the default look.
Behavior
- Repeated images share one dialog. The dialog
idis a stable hash of the imagesrc, so referencing the same image more than once produces a single dialog that every trigger opens — not a duplicate per reference. - Name a lightbox with
{#id}. With remark-attrs (or any compatible attrs plugin),!{#hero}usesheroas the dialogidinstead of the hashed default. Run the attrs plugin beforerehypeLightbox. - Images inside a link are skipped. A
<button>can't nest in an<a>, so a linked image ([!](/page)) renders as a normal linked image and the!stays literal.
Customization
The stylesheet exposes public custom properties:
| Property | Default | Description |
| ------------------------------ | ------------------ | -------------------------------- |
| --markdown-lightbox-backdrop | rgb(0 0 0 / 72%) | Backdrop color behind the image. |
| --markdown-lightbox-blur | 3px | Backdrop blur radius. |
| --markdown-lightbox-radius | 0.375rem | Image corner radius. |
| --markdown-lightbox-duration | 0.25s | Open/close transition duration. |
Browser support
Requires command/commandfor, <dialog closedby>, and @starting-style
(Chromium 135+ and equivalent). Where unsupported, images degrade to a plain,
non-zooming thumbnail.
License
MIT © Drake Costa
