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.
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-nameattribute likedata-name="A14"with the row and seat number. The data is right there. - Suggested fix
- Add an
aria-labelto 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 addrole="button"andtabindex="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.