Plate № 23 · UX · media / lightbox

A pattern from the gf.cx specimen book

Thumbnail → modal enlargement

Source · Dan, 2026-07-09

"can we convert this to a pattern-modal, and store it on assets.gf, and talk about it on patterns.gf?"

The problem

A page grows a thumbnail — a locator map, a facility photo, a hand-drawn diagram — and the reader wants it bigger. So you build a modal: an overlay, a close button, backdrop-and-Escape handling, focus return, body-scroll lock, a caption. It works. Then the next page needs one, and the one after that, and each gets its own slightly-different copy: this one traps focus, that one forgets to restore scroll, a third uses a z-index that a tooltip pokes through. The behaviour is identical every time; only the bugs differ.

The same drift the provenance footer and back-to-top icon kill, one layer up: a UI affordance that should be one shared thing, hand-copied into many. The fix is the same — lift it to a single CDN-hosted primitive, mark the thumbnail with a data attribute, and let the shelf own the overlay.

The element, in-page

The live specimen below runs in a sandboxed iframe (the pattern-preview primitive). Click either thumbnail to open the enlargement; close with the ×, a click on the backdrop, or Escape. Tab to a thumbnail and press Enter — it opens too. One overlay serves every thumbnail on the page.

How you use it

Link the shared css + js once, then mark any thumbnail data-modal. No overlay markup, no per-page script:

<link rel="stylesheet" href="https://assets.gf.cx/modal/modal.css">
<script src="https://assets.gf.cx/modal/modal.js" defer></script>

<figure class="modal-thumb" data-modal
        data-modal-src="…/map.png"
        data-modal-caption="Locator — Josefstrasse 225. © OpenStreetMap">
  <img src="…/map.png" alt="Locator map">
  <figcaption>Josefstrasse 225</figcaption>
</figure>

What gets enlarged, first match wins: data-modal-src (an image URL) → data-modal-node (a CSS selector to clone — e.g. an inline <svg> shown small) → otherwise the trigger's own first <svg> or <img>. Caption falls back to the trigger's <figcaption>.

Where it applies

Reusable elements

The named, copyable pieces — lift any one without the others:

Reference

Source
Dan, 2026-07-09 — "convert this to a pattern-modal, store it on assets.gf, talk about it on patterns.gf". Distilled from the bespoke modal built for srvc.gf.cx/transit the same day, then lifted to the shelf.
In use / example
srvc.gf.cx/transit — facility Visuals disclosures (map + building photo) and the leaf-spine fabric diagram all open through the shared modal. Shelf source: assets.gf.cx/modal/.
Reusable elements
Shared CDN css+js · data-modal attribute API · node-clone enlargement · progressive-enhancement a11y · .modal-thumb affordance (listed above).
Origin
An event-delegated modal hand-wired into srvc.gf.cx/transit (2026-07-09) for locator maps + an inline-SVG diagram. Generalised the same day to a shelf primitive. Sibling of the back-to-top jump icon and built-with provenance footer — the same single-source, control-plane discipline applied to a different page layer.
Build cost
~30 min to lift the bespoke modal to the shared css+js and migrate the origin page; ~1 line + a data-modal attribute per new thumbnail thereafter.