Skip to content

Add image lightbox for documentation images - #47352

Open
fdmarcin wants to merge 7 commits into
currentfrom
msj-lightbox
Open

Add image lightbox for documentation images#47352
fdmarcin wants to merge 7 commits into
currentfrom
msj-lightbox

Conversation

@fdmarcin

@fdmarcin fdmarcin commented Aug 11, 2026

Copy link
Copy Markdown
Member

Proposed change

Add a lightbox for larger documentation images, so screenshots can be opened and zoomed without leaving the page.

The implementation uses PhotoSwipe 5.4.4, vendored into the website and served locally. A small adapter enables it only for substantial images inside documentation and blog articles. It skips linked images, buttons, small inline images, SVGs, and brand logos.

Navigation:

  • Click image to zoom in and zoom out.
    • On mobile: Tap to show controls, double-tap to zoom.
  • Keyboard left/right arrow to show prev/next image.
  • Esc to close the modal.

Privacy and maintainability notes:

  • No CDN is used, so opening an image does not call a third-party service.
  • PhotoSwipe is MIT licensed. Its license is included with the vendored files.
  • The adapter keeps site-specific behavior separate from the library code.
  • The vendored README documents the update commands and the version string to change.

Alternatives considered:

  • Loading PhotoSwipe from a CDN: simpler, but adds a third-party request.
  • Adding PhotoSwipe only to package.json: this site does not bundle or serve files from node_modules, so that would not work by itself.
  • Adding a build copy step from node_modules: workable, but more moving parts for this static Jekyll site.
  • Keeping the custom vanilla lightbox: less dependency risk, but more accessibility and browser behavior to maintain ourselves.
image

Comparisons

Before After
Getting started: Automations Getting started: Automations
Integration: Cover Integration: Cover
Dashboard: Energy Dashboard: Energy
Blog post Blog post

Type of change

  • Spelling, grammar or other readability improvements (current branch).
  • Adjusted missing or incorrect information in the current documentation (current branch).
  • Added documentation for a new integration I'm adding to Home Assistant (next branch).
  • Added documentation for a new feature I'm adding to Home Assistant (next branch).
  • Removed stale or deprecated documentation.

Additional information

Checklist

  • This PR uses the correct branch, based on one of the following:
    • I made a change to the existing documentation and used the current branch.
    • I made a change that is related to an upcoming version of Home Assistant and used the next branch.
  • The documentation follows the Home Assistant documentation standards.

@home-assistant home-assistant Bot added the current This PR goes into the current branch label Aug 11, 2026
@netlify

netlify Bot commented Aug 11, 2026

Copy link
Copy Markdown

Deploy Preview for home-assistant-docs ready!

Name Link
🔨 Latest commit 72ed2d9
🔍 Latest deploy log https://app.netlify.com/projects/home-assistant-docs/deploys/6a82f8aa6bccf90008a42c30
😎 Deploy Preview https://deploy-preview-47352--home-assistant-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@fdmarcin
fdmarcin marked this pull request as ready for review August 11, 2026 13:17
Copilot AI lite review requested due to automatic review settings August 11, 2026 13:17
@fdmarcin

fdmarcin commented Aug 11, 2026

Copy link
Copy Markdown
Member Author

@mrdarrengriffin Hi! Would you mind giving this a look? I'm not sure whether vendoring this is the best approach.

This isn't urgent.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an on-page image lightbox for documentation and blog images by vendoring PhotoSwipe and wiring it into the site so readers can open/zoom screenshots without navigating away.

Changes:

  • Vendor PhotoSwipe (JS + CSS) locally and include MIT license + update instructions.
  • Add a small adapter (image-lightbox.js) that makes eligible images interactive and opens them in PhotoSwipe.
  • Hook the feature into the global site layout (CSS in <head>, JS in scripts include, plus SCSS overrides for focus/cursor).

Reviewed changes

Copilot reviewed 9 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
source/stylesheets/photoswipe/photoswipe.css Vendored PhotoSwipe stylesheet.
source/stylesheets/photoswipe/LICENSE MIT license copy for the vendored stylesheet.
source/javascripts/photoswipe/README.md Documents vendoring/update procedure and version sync point.
source/javascripts/photoswipe/photoswipe.esm.min.js Vendored PhotoSwipe core module (minified).
source/javascripts/photoswipe/photoswipe-lightbox.esm.min.js Vendored PhotoSwipe lightbox module (minified).
source/javascripts/photoswipe/LICENSE MIT license copy for the vendored JS.
source/javascripts/image-lightbox.js Site adapter: selects eligible images, adds keyboard/click handling, and opens PhotoSwipe.
source/_includes/site/head.html Adds the PhotoSwipe CSS to the site head.
source/_includes/javascripts/scripts.html Loads the image lightbox adapter site-wide.
sass/homeassistant/base/_image_lightbox.scss Adds focus-visible styling and minor PhotoSwipe overrides.
sass/homeassistant/_homeassistant.scss Includes the new lightbox SCSS in the main bundle.
Suppressed comments (1)

source/javascripts/image-lightbox.js:211

  • If the dynamic import fails (offline, blocked request, etc.), this promise rejection will currently bubble up as an unhandled rejection. Add a catch around the open call (even a no-op) to avoid noisy console errors and keep the page functional.
    event.preventDefault();

    getLightbox().then((lightbox) => {
      lightbox.loadAndOpen(
        index,
        getLightboxItems(images),
        getInitialPoint(event)
      );
    });

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread source/javascripts/image-lightbox.js

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (4)

source/javascripts/image-lightbox.js:74

  • The filename heuristic also excludes substantial screenshots whose names contain logo or brands. For example, custom_logo.png and supported-brands.png are screenshots with screenshot alt text, but both fail this check. Apply the existing screenshot exception to the path heuristic as well so these images remain eligible.
      /(?:^|[-_/])(logo|logos|brand|brands|wordmark)(?:[-_.\/]|$)/i.test(path) ||
      ((/\blogo(s)?\b|\bwordmark\b/.test(alt)) &&
        !alt.includes("screenshot"))

source/javascripts/image-lightbox.js:173

  • The PhotoSwipe root is created with role="dialog", but neither the vendored module nor this adapter gives it an accessible name. As a result, screen readers announce an unnamed dialog. Register a PhotoSwipe lifecycle handler (for example, uiRegister) that sets an aria-label such as “Image viewer” on lightbox.pswp.element.
          return new PhotoSwipeLightbox({

source/javascripts/image-lightbox.js:196

  • The PR description says a tap zooms the image in and out, but this setting makes a single tap only toggle the controls; zoom requires a double-tap or pinch. Set the tap action to zoom, or update the documented interaction if the current behavior is intentional.
            tapAction: "toggle-controls",

sass/homeassistant/base/_image_lightbox.scss:10

  • Many documentation screenshots are inside p.img, which has overflow: hidden; when an image fills that container, this outward focus outline is clipped on the container edges. Use an inset outline so keyboard users retain a visible focus indicator.
      outline-offset: 4px;

@fdmarcin

Copy link
Copy Markdown
Member Author

I also asked in HA Discord for a Designer review.

@fdmarcin
fdmarcin requested review from a team and a balanced review from Copilot August 17, 2026 09:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (1)

source/javascripts/image-lightbox.js:205

  • The viewer traps focus and blocks interaction with the page, but PhotoSwipe creates only role="dialog"; this handler adds a label without identifying it as modal. Assistive technologies may therefore continue exposing the underlying page as active content. Set aria-modal="true" on the dialog element when registering the UI.
          lightbox.on("uiRegister", () => {
            lightbox.pswp.element.setAttribute("aria-label", "Image viewer");
          });

image.naturalWidth &&
image.naturalHeight &&
!image.closest("a, button") &&
!image.closest(".no-lightbox, [data-no-lightbox]") &&

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we document this opt-out somewhere (create page doc ?)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@piitaya Sure, I'll open a PR

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread source/javascripts/image-lightbox.js Outdated
Comment on lines +64 to +65
const alt = (image.getAttribute("alt") || "").toLowerCase();
const isScreenshot = alt.includes("screenshot");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alt text is the wrong place for it. It describes the image for screen reader users, and once it also controls the lightbox, people will write "screenshot" to get the zoom rather than to describe the image.

It also does nothing today. I wan not find any image matching the logo path or alt rules contains "screenshot", so it changes the outcome for zero images.

Can we drop isScreenshot? If a real screenshot ever gets caught, an explicit opt-in would be clearer, and symmetric with data-no-lightbox.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@fdmarcin
fdmarcin requested a review from piitaya August 17, 2026 12:12
@home-assistant home-assistant Bot added the has-parent This PR has a parent PR in another repo label Aug 17, 2026
@fdmarcin fdmarcin removed the has-parent This PR has a parent PR in another repo label Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

current This PR goes into the current branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The text in the screen shots is way too small to read easily

3 participants