Users with visual impairments on iPhone rely on headings as the primary navigation landmarks for browsing web pages. The VoiceOver Rotor lets users choose a navigation mode by rotating two fingers on the screen. When "Headings" is selected, VoiceOver can jump directly between headings on a page, letting users skim articles without reading every word.
Rotor heading navigation is broken on Wikipedia for iOS VoiceOver users. When a user selects "Headings" from the Rotor on a Wikipedia article, only the page title is surfaced. All article section headings are invisible to VoiceOver, which responds with an error haptic and says "heading not found". This is a critical accessibility regression that removes a fundamental navigation mechanism for blind and low-vision users.
User report (via Slack thread, forwarded to accessibility mailing list):
Hello Wikipedia team, my name is Diego and I am visually impaired and a VoiceOver user of iOS devices. Recently, on Wikipedia articles when I browse them, I cannot browse by headings within the rotor option. It gives me an error haptic feedback and it says "heading not found." This issue is affecting many VoiceOver users. I hope it can be resolved soon. — Diego (using Safari on iOS)
Steps to replicate the issue:
- Open Safari on an iPhone with VoiceOver enabled (Settings > Accessibility > VoiceOver > On, or ask Siri: "Turn on VoiceOver")
- Navigate to any Wikipedia article with multiple sections (e.g. https://en.wikipedia.org/wiki/Paris)
- Once the page has loaded, activate the VoiceOver Rotor by rotating two fingers on the screen
- Swipe through Rotor options until you reach "Headings"
- With "Headings" selected, swipe down with one finger to jump to the next heading
What happens?:
- VoiceOver produces an error haptic feedback and announces "heading not found"
- Only the page title and "Related Articles" headings are surfaced.
| broken headings | functional headings |
On desktop, a screen reader user can navigate to all headings using the Headings mode:
* Historiography * Development of the theory in the 19th century * Kenneth McIntyre and development of the theory in the 20th century * Purported evidence and arguments * Interpretation of the Dieppe Maps * etc...
On mobile the screenreader only sees the page title and "related articles" heading on the page, followed by "Heading not found".
What should have happened instead?:
- VoiceOver should announce each section heading (e.g. "History, heading level 2") in sequence as the user swipes
- The user should be able to jump between all article sections using Rotor heading navigation
- This is standard, expected behaviour on any well-structured web page and works correctly on desktop with screen readers such as NVDA/JAWS
Developer notes
History
This patch fixed T395024 (arguably a worse accessibility issue where screen reader users were unaware of content in collapsed sections) by moving aria-expanded and related attributes from a non-existent element to the mw-heading div that wraps the heading element. It introduced the current issue for reasons detailed below.
Current markup
<div class="mw-heading mw-heading2 section-heading collapsible-heading open-block" tabindex="0" role="button" aria-controls="content-collapsible-block-1" aria-expanded="true"> <span class="mf-icon mf-icon-expand mf-icon--small indicator mf-icon-rotate-flip"> </span> <h2 id="History">History</h2> </div>
1. role="button" collapses all children into a single accessible element
When you put role="button" on a <div> element, VoiceOver treats the entire div as one interactive element. That means:
- The heading inside is no longer navigable as a heading
- The user cannot use Rotor navigation ("Headings") to jump to it
- VoiceOver may read the heading text as the button label, but it loses semantic structure
This is a loss of structural semantics, which is bad for navigation and for users who skim by headings.
2. Buttons cannot contain headings
According to ARIA and HTML accessibility mapping rules:
Interactive controls should not contain block-level sectioning content (like <h1>–<h6>).
This is handled inconsistently across screen readers. On VoiceOver for iOS specifically:
- The whole element is treated as a single button
- The inner heading is not exposed as a heading role
- Only the first text node is often read as the accessible name
This causes the heading to be ignored entirely in the Rotor heading navigation tree.
Technical best-practice reference
https://www.w3.org/WAI/ARIA/apg/patterns/accordion/
Acceptance criteria
- Headings are correctly identified by the Rotor "Headings" option on iOS VoiceOver
- Heading navigation works consistently across collapsed and expanded section states
- Accessibility mailing list / users have been notified of the fix


