Rethinking Find-in-Page Accessibility: Making Hidden Text Work for Everyone
I regularly attend UX Graz (Meetup / LinkedIn), a meetup covering diverse UX-related topics, alternating between in-person and remote events. At one recent event, a blind speaker demonstrated how they navigate websites (on LinkedIn). It wasn't my first time seeing someone blind use assistive technology for web navigation, but this experience stood out. Instead of relying on semantic elements like landmarks, headings, lists, or links, the speaker primarily used the browser's find-in-page functionality to navigate.
This approach surprised me at first. As frontend developers, we've been taught to focus on semantic HTML to aid navigation for assistive technology users. But the more I thought about it, the more it made sense: find-in-page can be a much faster and more efficient way to locate content, especially when semantic structures are missing or are poorly implemented. However, this technique isn't foolproof. It falters when text is hidden using attributes like aria-label
, title
, or alt
, or when visible text is styled with font-size: 0
- a method I often use for icon-only buttons.
The event left a lasting impression and plenty to think about.
Fast forward to last week: my podcast co-host, Vanessa, messaged me about our Slack community. She needed the invite link, knew it was on our homepage, and hit Cmd
+ F
to search for "Slack." Yet, nothing came up.
The issue? Once again, the text label for the Slack link was hidden using font-size: 0
, as shown in this snippet:
<a href="https://draft.community" style="font-size: 0">
<svg.../> Slack
</a>
Vanessa asked:
"Is it possible to solve this on the frontend so that the icon gets focused when you use Cmd+F to search for a specific term?"
This reminded me of the meetup speaker's navigation pattern. When I told her about it, this is what she replied:
"Honestly, I use websites exactly the same way."
The Solution: hidden="until-found"
#
I had an idea to fix this problem using a relatively new HTML feature: the hidden="until-found"
attribute. Added to the HTML standard in March 2022, it was shipped in Chrome 102 (May 2022).
The hidden="until-found"
attribute works similarly to display: none
, preventing the element from rendering or taking up space. However, unlike display: none
, the content remains in the accessibility tree, can be found via find-in-page, and is also targetable via anchor links. When a matching search or anchor link is triggered, the hidden
attribute is removed, and the element becomes visible.
Here's how I updated our icon-only buttons:
<a href="https://draft.community">
<svg.../>
<span class="hidden-until-found" hidden="until-found">Slack</span>
</a>
Now, the text label is searchable. If matched during a search, it appears dynamically. For a more pleasing user experience, I added a tooltip-like rendering for the revealed text using CSS:
.hidden-until-found:not([hidden="until-found"]) {
position: absolute;
transform: translateX(calc(-50% - (var(--icon-width) / 2)));
margin-top: -0.25rem;
padding: 0 0.2rem 0.05rem 0.2rem;
background-color: var(--brand-color);
color: #fff;
border-radius: 0.1rem;
font-size: 1rem;
filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.5));
}
/* little pointer at the bottom */
.hidden-until-found::after {
content: '';
position: absolute;
z-index: -1;
left: 50%;
bottom: -0.2rem;
width: 1rem;
height: 1rem;
transform: translateX(-50%) rotate(45deg);
background-color: inherit;
}
The result 😍:
Browser Compatibility and Accessibility #
Currently, hidden="until-found"
is only supported in Chromium-based browsers. In Firefox and Safari, the element behaves like a standard hidden
attribute, meaning it isn't accessible via assistive technology, searchable, or linkable. While the latter two are tolerable (since they match the previous behavior), losing assistive tech accessibility is a problem.
To address this, I added an aria-label
to ensure assistive technology still recognizes the link:
<a href="https://draft.community" aria-label="Slack">
<svg.../>
<span class="hidden-until-found" hidden="until-found">Slack</span>
</a>
Thankfully, hidden="until-found"
is part of this year's Interop project, representing one puzzle piece amongst many to align all browsers on the <details>
element. If end of 2025 appears too late for you, consider weighing in on the WebKit and Mozilla bug trackers.
Remaining Challenges #
-
Persistent Text Visibility: Once text is revealed via find-in-page, it remains visible even after closing the search or starting a new one. Unfortunately, there's no native way to hide it again. A potential workaround is to listen for the
beforematch
event and reapplyhidden="until-found"
after a certain delay. -
Styling Search Matches: It's currently impossible to style matched text directly. However, future CSS pseudo-elements like
::search-text
and::search-text:current
could allow fine-grained control over search result styling.
This episode taught me the importance of accommodating diverse navigation patterns and highlighted (once more) how evolving standards can improve accessibility for everyone. But while hidden="until-found"
is a good step forward, there's still work to be done to make find-in-page truly universal.
Webmentions





-
As for slides, there weren't any, except for an introduction by an agency that offers accessibility testing services with disabled testers, amongst which Christian. But the organizer, Johannes Lehner knows more: www.linkedin.com/in/jbeargrap...
-
The LinkedIn one worked, thanks! And yeah, I think I know the folks. Looks like it was an intro session, which is great for people to see. Thanks!
-
My bar for celebrating with cake is pretty low, maybe that helps. Either way, nice post!
-
Ah yeah it has to be a has enabled pseudo element or something which might be basically nothing right now? I think its to prevent cycles where your CSS changes the existence of a pseudo element. Perhaps that new one will be has enabled?
-
It could be a candidate for the/an enabled-list as it is a pseudo element that you can't create yourself and therefore should not mistakenly lead to cycles. To be sure that :has() would not work I checked with the ::target-text pseudo element which is similar. It indeed did not work.
-
Alternativtext macht Kaffeedurst 3
-
Bei NVDA ist das "müsste" eventuell richtig. Bei JAWS wäre ich mir da nicht so sicher. Bisher stimme ich @tcaspers.bsky.social zu, dass der Link leer wäre. Aber da zählt auch der Sonnenstand und die Raumtemperatur mit rein.
-
Ach so, und ich denke übrigens, dass Du so oder so unterkoffeiniert bist und dringend einen weiteren Espresso brauchst. So wie ich auch :)
-
ROFL!
-
Hach ja, die Untiefen der ARIA Spec, wir lieben es. Könnte tatsächlich sein – das Vorhandensein von aria-label oder ein fokussierbares Element führen ja auch dazu, dass anderes Gedönse wie role=presentation ignoriert wird, vielleicht gilt das ja auch für hidden. Hab nur gerade keinen JAWS zur Hand.
-
Aber ich update den Artikel gerne, wenn es anders besser wäre.
-
Oh, that's an intriguing idea! Gonna explore that one. I also had thought of .hidden-until-found:has(::search-text:current) to at least solve the problem in the future, but I scrapped the idea the moment I realized that :has() does not allow pseudo elements as selectors (like :is() and :where())
-
If you used popovers for the labels you could rely on the only one being open at once behaviour along with a toggle event listener to readd hidden until found to the label? Could call showPopover from the beforematch event?
-
One potential solution to rehide is to add an event listener for the blur (or focus out etc) event to the anchor and then re-add the attribute in it?
-
Dam this could legit replace sr-only/visually-hidden utilities
-
Another use case could be searching through content in accordions. A few months back, I had to implement a specific custom search feature just because of CtrlF not working for this case.
-
Eventuell bin ich noch unterkoffeiniert, aber ist das Codebeispiel hier schepp.dev/posts/rethin... dann nicht aus Screenreader-Sicht trotzdem ein leerer Link?
-
I'd think so, too!
-
Ich will gar nicht wissen, was JAWS daraus macht ehrlich gesagt. Wo doch dieser SR so wunderbar und fehlerfrei funktioniert. NOOOOOT.
-
That sounds like an approach to explore. Although I had the browser console.log the document.activeElement to me during find-in-page and cycling through results, and focus did not move to the result until one taps the enter key.
-
Gemäß www.w3.org/TR/accname/#... müsste das mit `aria-label` funktionieren und ich hab das Konstrukt auch in der Accessibility Tree Ansicht von Firefox inspiziert und da war der `name` gesetzt (bzw. nach meinem Fix wieder gesetzt und vorher nicht). Es erschien mir demnach gut so.
-
That is exactly what it was invented for: developer.chrome.com/docs/css-ui/...
-
Ah, der Schepp teilt nen Link. Moment …! Der Schepp teilt einen eigenen Post! ????????????
-
????
-
Ist bei den ATs nicht entscheidend, was im Accessibility Tree ankommt? Falls ja, müsste es denen ja dann egal sein, auf welchem Weg es dort ankommt.
-
It's ok to celebrate with cake right?
-
The link to the Meetup event requires a login to see it (because I was curious the presenter, topic, and possible slide links) but I burned my Meetup account a while ago. Also, FWIW, I consider `aria-label` to be so risky that I would not use it as an interim approach. I’m waiting for the interop.
-
Here is an alternative link to the event on LinkedIn, if that's better for you: www.linkedin.com/events/remot... I'll add it to the post as well. If you are interested in the name of the presenter, I only got to learn him as "Christian".
-
Yes! I took would quite like this + searchable details. I actually proposed both to Interop so I'm glad it was accepted. Hopefully given the relatively smaller surface area compared to other focus areas it might come sooner.
-
I'm definitely stealing that hidden until found icon labels idea!
-
Great read. It terrifies me to know that folks actually rely on find-in-page for accessibility, though it totally makes sense, because WebKit’s implementation of `content-visibility: auto` is broken for find-in-page.
-
Worth noting in supporting browsers the details html element also gives you find-in-page support out the box. So for the more conventional disclosure widget UI, you can just use that.
-
So, a feature that’s meant to be a quick win and a progressive enhancement for performance without affecting accessibility or findability, now breaks the web experience for these users.