Skip to content

Image modal cannot be opened or operated by keyboard #1258

Description

@hiyach28

Raised by CodeRabbit on #1253. Filing separately because the gap predates that PR and fixing it properly is larger than the one-line change suggested there.

The gap

Markdown images open a lightbox modal on click (layouts/_default/_markup/render-image.html plus layouts/partials/image-modal.html). An <img> is not focusable, and the handler in the partial binds only onclick, so a keyboard user cannot open the modal at all.

The modal itself has no focus management either:

  • openModal sets the source and displays the overlay, but never moves focus into it
  • focus is not trapped, so tabbing continues through the page behind the overlay
  • focus is not restored to the triggering image on close
  • Escape does close it, which is the one piece already in place

So the whole interaction, not only the trigger, needs work.

Why the suggested one-liner is not the fix

The proposal on #1253 was:

<img role="button" tabindex="0" aria-label="Open image in modal" onkeydown="..." alt="{{ .Text }}">

role="button" replaces the implicit img role, and aria-label overrides alt. A screen reader user would hear "Open image in modal, button" on every figure and never hear the alt text describing it. That trades a keyboard gap for a content gap, on all 380 Markdown images.

It would also make every image on a page a tab stop. Some pages here carry 20 or more images, so that is a real navigation cost and worth a deliberate decision rather than a side effect.

Suggested direction

Wrap the image in a real control rather than relabelling the image:

<div class="md__image">
  <button type="button" class="md__image-trigger" aria-label="Expand image">
    <img src="..." alt="{{ .Text }}" class="md-image-responsive">
  </button>
</div>

A native <button> brings focus, Enter and Space for free, and the <img> keeps its own role and alt. It needs a small CSS reset so the button does not draw its own box, and .md__image img styling already applies through it.

Then in the partial: move focus to the close button on open, trap Tab within the overlay, and return focus to the trigger on close.

Worth deciding at the same time whether every image should be expandable, or only ones marked for it, given the tab-stop cost.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions