All case studies

Web application accessibility review

Movie theater seat map: it works, but I'm picking seats with missing information.

I go to this theater regularly. The seat map actually works with VoiceOver -- I can hear the row letters, seat numbers, and check boxes to pick seats. But I can't tell if a seat is taken, what type it is, or jump to a specific row. Sighted users see all of that instantly in a color-coded grid.

Platform Web (SaaS ticketing platform)
Testing tools VoiceOver, keyboard, DOM inspection
Severity Usability gap

What this case study shows

The seat map mostly works. It's just missing information.

The checkboxes work. The row letters are in the page. The data for seat type and availability is already in the code. It's just not connected to what the screen reader reads.

What to notice

  • The seat map works but is missing context
  • The fix is small: aria-labels and headings
  • I built a working before/after demo
  • This is a SaaS platform, so one fix helps every theater using it

What already works

Checkboxes are real checkboxes

Each seat is an actual input element. VoiceOver can find them and interact with them.

Row letters are present

The letters A through J are in the page between each row of seats. VoiceOver reads them as you arrow through.

Seat numbers are there

Each checkbox has the seat number as text next to it. VoiceOver picks it up.

Findings

Checkboxes have no accessible name

Usability gap
Issue
The checkbox inputs have no aria-label, no title, no associated label element. The seat number is a separate span next to the checkbox. VoiceOver reads the number as you pass it, but the checkbox itself is unlabeled.
What I hear
"A... 14, unchecked checkbox... 13, unchecked checkbox..." I can piece together the row and seat, but it takes work.
What's in the code
Each checkbox has a data-name attribute like data-name="A14" with the row and seat number. The data is right there.
Suggested fix
Add an aria-label to each checkbox: "Row A, Seat 14, love seat, available." The data-name attribute already has the row and seat. The parent div's CSS class has the seat type (LoveSeatLeft, Wheelchair, etc).

No way to tell if a seat is taken

Usability gap
Issue
Sighted users see taken seats as gray and available seats as orange. VoiceOver doesn't convey this. All seats say "unchecked checkbox" whether they're available or not.
Suggested fix
Disable taken seat checkboxes and include availability in the aria-label. "Row C, Seat 5, love seat, taken" vs "Row C, Seat 5, love seat, available."

No way to jump to a specific row

Usability gap
Issue
If I want Row F, I have to go through every seat in rows A through E first. That's 70+ checkboxes. There's no way to skip ahead.
Suggested fix
Make the row labels (A, B, C...) into heading elements. Then VoiceOver heading navigation (VO+Cmd+H) jumps directly to any row.

Seat type not communicated

Usability gap
Issue
Some seats are love seats, some are wheelchair spaces, some are standard. This is only communicated through CSS classes (LoveSeatLeft, Wheelchair) and visual icons. VoiceOver doesn't know.
Suggested fix
Include the seat type in the aria-label. The CSS class already has the information.

Purchase Tickets and Deselect All aren't proper buttons

Usability gap
Issue
Purchase Tickets is an anchor tag with no href. Deselect All is a div. Neither is a real button element.
Suggested fix
Use <button> elements, or add role="button" and tabindex="0".

I built a working demo

I took the seat map HTML and CSS, fixed the accessibility issues, and made a local before/after version. The fixed version adds aria-labels to every seat, headings for each row, and disables taken seats. The visual design doesn't change at all.

What the fix actually involves

aria-labels on checkboxes

One attribute per seat, built from data already in the code. "Row A, Seat 14, love seat, available."

Row headings

Change the row letter spans to heading elements. No visual change. Adds heading navigation for screen readers.

Disable taken seats

Add the disabled attribute to taken seat checkboxes and include "taken" in the aria-label.

Platform-wide impact

This seat map is part of a ticketing platform used by multiple theaters. The code is shared, so one fix applies everywhere.

Summary

  • The data for a full fix is already in the code
  • The visual design doesn't need to change
  • One fix rolls out to every theater on the platform
  • Probably an hour or two of development work

Need this kind of review?

I test websites and apps with VoiceOver and write up what I find.