DEV Community

OnePassApps
OnePassApps

Posted on Edited on

The Reference Layer of app.onepassapps.com: 150 ARIA Pointers, 13 Targets and Not One Dangling

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
  • /plans carries eight
  • /guides carries 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.

the plans page

one guide page

Top comments (0)