Open gallery images in a native dialog modal

Medium completed
2026-06-03 agentics feature Medium effort

Make the media library's "View image" control open each card's PNG in a native <dialog> modal overlay instead of navigating to a new browser tab — keeping the user in the gallery for fast, distraction-free previewing.

Implement Read and implement all steps in the plan at docs/plans/add-image-dialog-modal.md — Open gallery images in a native dialog modal. Verify against the plan's Tests, Verification, and Acceptance Criteria before reporting done. If everything passed, mark completion in docs/plans/add-image-dialog-modal.md — tick each step's [x] marker and each criterion's - [x], set status: completed — and re-render the HTML from the spec. If any check failed, leave status: in-progress and say which.
More ways to run this plan — goal & workflow prompts, file path
Pursue as goal — optimize for the outcome
Achieve this goal: Open gallery images in a native dialog modal. The plan at docs/plans/add-image-dialog-modal.md describes one approach — use it as reference, but optimize for the outcome. Verify against the plan's Tests, Verification, and Acceptance Criteria before reporting done. If everything passed, mark completion in docs/plans/add-image-dialog-modal.md — tick each step's [x] marker and each criterion's - [x], set status: completed — and re-render the HTML from the spec. If any check failed, leave status: in-progress and say which.
File add-image-dialog-modal.html
Path docs/plans/add-image-dialog-modal.html
Spec docs/plans/add-image-dialog-modal.md
Definition of done 8 / 8 done

Context

The story behind this plan — what prompted the work and why it matters now.

The media-library skill ( kit/plugins/social-media-tools/skills/media-library/SKILL.md ) builds an HTML gallery of saved social cards from the gallery.html template ( kit/plugins/social-media-tools/templates/gallery.html ). v2.7.0 added a "View image" link below each card that opens the card's .png screenshot.

Today that link is an anchor — <a class="open-img-link" href="…png" target="_blank" rel="noopener"> — so clicking it leaves the gallery and opens the image in a new tab. The goal is to preview the image inline via a modal overlay without losing gallery context.

Confirmed decisions: the modal shows the image only (no caption); the feature is JavaScript-only with no new-tab fallback (the trigger becomes a <button> with no href ); released as a minor bump, 2.8.0 → 2.9.0.

Both the template's static markup AND the skill's generation step reference .open-img-link , so converting the anchor to a button requires editing SKILL.md Step 3 as well as the template. The browser's native <dialog> element with showModal() provides focus trapping, background inertness, and Escape-to-close for free — no library needed.

Steps

The step-by-step work, in order — each step says what to do, why it matters, and how to check it worked.

1
done Add the shared <dialog id="imgDialog"> element and its CSS to the gallery template
Why
A single reusable dialog (image + close button) shared by every card is lighter than one per card. CSS styles the backdrop, centers and scales the image to fit the viewport, and styles an accessible close button. Gate any fade/scale transition behind prefers-reduced-motion .
Verify
In templates/gallery.html , confirm one <dialog id="imgDialog"> exists before </body> containing an <img id="imgDialogImg"> and a close <button> with aria-label="Close" ; confirm dialog::backdrop and #imgDialog img rules exist with a max-width / max-height cap.
2
done Wire up open/close behavior via event delegation in the template's existing <script>
Why
Delegate click on the gallery for .open-img-link buttons: read data-img + data-topic , set #imgDialogImg src / alt , call imgDialog.showModal() . Close on the close button, on backdrop click ( e.target === dialog ), and natively on Escape. Native <dialog> restores focus to the trigger on close.
Verify
Reading the script, confirm a delegated listener opens the dialog from a clicked .open-img-link and that close handlers exist for the close button and a backdrop click. Confirm alt is set from data-topic so the image is labelled for screen readers.
3
done Change the "View image" generation in media-library/SKILL.md from an anchor to a button
Why
Step 3 of the skill currently emits <a class="open-img-link" href="{BASENAME_PNG}" target="_blank" …> . Replace with <button type="button" class="open-img-link" data-img="{BASENAME_PNG}" data-topic="{TOPIC}" aria-label="View image: {TOPIC}">View image</button> . Keep the existing rule that the element is only emitted when a matching .png exists.
Verify
In SKILL.md Step 3, confirm the documented markup is a <button> carrying data-img and data-topic (no href , no target="_blank" ), and that the "only include when PNG exists" condition is retained.
4
done Update .open-img-link CSS to style the button like the old link, and bump version + changelog
Why
The existing .open-img-link CSS targets an anchor; reset button defaults ( background:none; border:0; cursor:pointer; font:inherit; width:100% ) so the button keeps the same centered blue "View image" look. Then bump social-media-tools 2.8.0 → 2.9.0 in .claude-plugin/marketplace.json and add a v2.9.0 entry to the plugin CHANGELOG.md .
Verify
Confirm .open-img-link renders identically to before (centered, blue, hover underline) as a button. Confirm marketplace.json shows "version": "2.9.0" for social-media-tools and CHANGELOG.md has a dated v2.9.0 entry describing the dialog change.

Definition of done

The plan counts as done when every statement below is true — check each one off as you verify it.

Final check

One last pass to confirm the whole change works end to end.

After editing the template and skill, regenerate the gallery to exercise the real output path:

1. Run /social-media-tools:media-library — it rewrites docs/media/social/index.html from the updated template and opens it in the browser.

2. Click "View image" on a card that has a PNG (e.g. diff-rendering-pipeline-snapshot-fix-2026-06-02 ). Confirm the image opens in a centered modal over a dimmed backdrop, and the page does NOT navigate to a new tab.

3. Close it three ways: click the close button, click the dark backdrop outside the image, and press Escape. All must dismiss the modal.

4. Keyboard pass: Tab to a "View image" button, press Enter to open, confirm focus is inside the dialog and Tab stays trapped, press Escape, and confirm focus returns to the same button.

5. View source of the regenerated index.html and confirm the image triggers are <button class="open-img-link" …> elements, not anchors.

6. Confirm a card with no PNG ( session-merge-driver-2026-05-30 ) still renders with no "View image" control and no console errors.

Wrapping up

Three gates that must all pass before this plan is marked completed.

Required

Completion Report

No items to report — all requirements met.

Next steps

Follow-up ideas that came up along the way — none of them are required to finish this plan.

Apply the same dialog pattern to the plan-agent plans gallery

Paste this prompt into Claude to execute this follow-up:

The plan-agent plugin builds a plans gallery (plans-library skill, kit/plugins/plan-agent/...). Audit whether it has any "open in new tab" image or preview links, and if so apply the same native <dialog> modal pattern used in social-media-tools' gallery.html so previews open inline. Keep it image-only and JavaScript-only, matching the social-media-tools implementation. Bump plan-agent's version and changelog accordingly.
Full lightbox: prev/next navigation, captions, and pinch-zoom Wish List

Speculative / blue-sky idea — not on the critical path. Paste into Claude when ready to explore:

Paste this prompt into Claude to execute this follow-up:

Extend the media library image dialog into a full lightbox: add prev/next arrow buttons (and Left/Right arrow keys) to browse all cards' images without closing the modal, show the card topic and date as a caption, and support pinch-zoom / click-to-zoom on the image. Keep keyboard accessibility and focus trapping intact. Implement in templates/gallery.html and bump the plugin version.