I work on OnePassApps, the team behind app.onepassapps.com, so this is a measurement of our own site. Everything below was measured on 9 November 2026 with plain HTTPS from one network - no session, no cookies, no JavaScript, one build, one edge.
We have written about the id layer, the class layer, the link layer, the JSON-LD identity layer, the landmark layer and the data-attribute layer of these 56 pages. This one is about the layer that points: the ARIA attributes whose value is the id of another element rather than a description of this one.
An aria-labelledby is a pointer. It says the accessible name of this element is the text of that one over there, and a pointer is only as good as its target. So this layer has two numbers that matter: how many pointers there are, and how many of them miss.
150 pointers across the fleet, and not one of them misses.
Only one pointer attribute is in use
Eight ARIA attributes can name another element: aria-labelledby, aria-describedby, aria-owns, aria-controls, aria-activedescendant, aria-flowto, aria-details and aria-errormessage.
Seven of them appear nowhere on the site. Not once, on any of the 56 pages. aria-describedby, the one you would reach for when a field needs a hint, is used zero times. aria-controls is used zero times. The fleet has exactly one pointer attribute in use, and it is aria-labelledby: 150 of them.
Every pointer lands
I resolved each of the 150 values against the id list of the same document, and all 150 resolve. There are no dangling references on app.onepassapps.com - no aria-labelledby names an id the page does not contain.
That is a smaller claim than it sounds, and it is worth being precise about it. It is a statement about the served HTML. It says nothing about what the app does after the bundle boots, and nothing about whether the heading a pointer names is the heading a reader would want.
150 pointers, 13 targets
The 150 pointers are not 150 separate decisions. They name 13 distinct ids, and the fleet reuses them heavily.
| Target | Points at | Pages carrying it | The heading text it resolves to |
|---|---|---|---|
shell-fallback-title |
h1 | 33 | OnePassApps stopped working in this tab |
features-heading |
h2 | 22 | What you can do |
steps-heading |
h2 | 22 | How to use this app |
limits-heading |
h2 | 22 | Limits and privacy |
questions-heading |
h2 | 22 | Common questions |
related-heading |
h2 | 22 | Related guides |
plan-free |
h2 | 1 | Free |
plan-standard |
h2 | 1 | Standard |
plan-pro |
h2 | 1 | Pro |
plan-questions |
h2 | 1 | Before you choose |
plan-question-credits |
h3 | 1 | What uses credits? |
plan-question-switch |
h3 | 1 | Can I switch plans later? |
plan-question-refunds |
h3 | 1 | How do refunds work? |
By tag, the 150 pointers resolve to h2 114 times, h1 33 times and h3 3 times. Every pointer names a heading. Not one names a button, a link, an input or a region.
The first row is the shell's fallback card - the section the startup shell carries in the served document on every page that boots the workspace. Its heading is the one element on the site whose id reads like a status message.
Where the pointers sit
Every one of the 150 aria-labelledby attributes sits on a <section> element. Not one is on a div, a nav or a button.
Per page the count is very uneven:
- 32 pages carry exactly one pointer
- 22 pages carry exactly five
-
/planscarries eight -
/guidescarries none
The 22 pages with five are the guide pages, and they name the same five headings every time: features-heading, steps-heading, limits-heading, questions-heading and related-heading. The single pointer on 32 of the remaining pages is shell-fallback-title, on the same 33 pages that boot the workspace - /plans carries that one too, plus seven of its own.
What a pointer buys you
On a guide page the markup is:
<section id="features" aria-labelledby="features-heading" class="gd-card">
with an <h2 id="features-heading"> holding the words What you can do inside it. The section's own id is features - the same word you would link to - and the accessible name comes from the heading, not from the id. id="features" is a destination; aria-labelledby="features-heading" is a name.
The related-guides section has no id of its own at all: <section aria-labelledby="related-heading" class="gd-related">. The plan sections on /plans are the same shape - a pointer and nothing else: <section aria-labelledby="plan-free">.
So the visible heading text is the name, and the id is only ever a place to jump to.
The one page with no pointers
/guides is the only page in the fleet with none of the 150. It holds no section element at all - the index is one main with a list of 25 items - and its three aria-label attributes name the site navigation, the breadcrumb and the legal-and-help region.
What this does not cover
One build, one network, one day, the served HTML only. I did not run an accessibility checker, I did not drive a screen reader, and I did not test the document after the JavaScript bundle boots. The claim that no pointer is dangling is about ids present in the response body - a pointer that resolves in the served document can still be attached to an element the app later replaces.
Two live examples, if you want to read the served markup yourself: the plans page, with eight pointers, and one guide page, with five.
Top comments (0)