
Stop Hiding Content with `display: none`: Why Your Accordions Need `hidden='until-found'` Instead
Keeping your collapsed UI searchable shouldn't require a hacky workaround or a sacrifice in your site's indexing potential.
I was trying to find a specific line in a sprawling FAQ section last week, hitting Cmd+F with increasing frustration. I knew the word "subscription" was on the page—I'd seen it earlier—but the browser kept telling me there were zero matches. The culprit was a series of sleek, "optimized" accordions using display: none to hide their contents.
We’ve all been there. We want a clean UI, so we tuck the heavy text away. But the moment you use display: none or visibility: hidden, you’re telling the browser: "Ignore this. Don't look at it, don't index it for find-in-page, and certainly don't let the user find it unless they manually click every single header."
It’s a bad experience. Thankfully, the HTML spec gave us a better way: the hidden="until-found" attribute.
The problem with the "Nuclear Option"
For years, display: none has been our go-to. It’s simple, it works, and it’s supported by every browser since the dawn of time. But it’s a blunt instrument. When an element is set to display: none, it is completely removed from the accessibility tree and the rendering pipeline.
If a user tries to search for a phrase hidden inside that element, the browser won't find it. The user assumes the information isn't there and bounces. You’ve successfully hidden your content from the very people trying to read it.
Enter hidden="until-found"
This attribute is a game-changer for discovery. When you apply hidden="until-found", the browser keeps the element hidden from view, but it stays "searchable."
If a user searches for text contained within that hidden section, the browser will:
1. Find the text.
2. Scroll the element into view.
3. Automatically remove the hidden attribute to reveal the content.
It’s like magic, but it’s just better HTML.
How to implement it
Instead of toggling a CSS class that sets display: none, you use the hidden attribute with the until-found value. Note that you also need to ensure the element isn't being forced to display: none in your CSS, as that will override the "until-found" behavior.
<!-- The Old, Broken Way -->
<div class="accordion-content" style="display: none;">
You'll never find me with Cmd+F!
</div>
<!-- The Better Way -->
<div id="faq-content" hidden="until-found">
I am hidden, but if you search for "hidden," I'll pop right open.
</div>The "Secret Sauce": The beforematch Event
When the browser finds a match inside a hidden="until-found" block, it fires an event called beforematch on the element before revealing it. This is your hook to update your UI—like rotating a chevron icon or updating the aria-expanded state on your accordion trigger.
Without handling this event, your content might appear, but your toggle buttons will look like they’re still closed.
const contentArea = document.querySelector('#faq-content');
const toggleButton = document.querySelector('#faq-toggle');
contentArea.addEventListener('beforematch', () => {
// The browser found a match!
// Let's update our UI state so the button matches the reality.
toggleButton.textContent = 'Collapse';
toggleButton.setAttribute('aria-expanded', 'true');
// Note: We don't need to manually remove the 'hidden' attribute.
// The browser handles that for us automatically.
});CSS Considerations
Here’s the catch: for hidden="until-found" to work, the element must technically have a display value that isn't none. The browser handles this internally, but if you have a global style like this:
/* This will break hidden="until-found" */
[hidden] {
display: none !important;
}...you’re going to have a bad time. The browser needs to be able to switch the element's state. When using until-found, the browser uses display: none specifically unless it's in that "searchable" state. To be safe, let the browser handle the default styling of the hidden attribute.
Why this is a massive win for SEO and UX
Search engine crawlers are generally smart enough to find content in display: none, but they often weight it lower because they assume it's less important to the user. By using hidden="until-found", you're signaling that this content is part of the page flow, just tucked away for visual clarity.
More importantly, it solves the "Where is it?" anxiety. Users love accordions because they reduce cognitive load, but they hate them when they can't find what they're looking for. This attribute gives you the best of both worlds: a clean, minimal interface and a perfectly searchable document.
Browser Support and Progressive Enhancement
As of right now, hidden="until-found" is primarily supported in Chromium-based browsers (Chrome, Edge, Opera).
"But what about Safari and Firefox?" I hear you.
This is a textbook case for progressive enhancement. If a browser doesn't support until-found, it treats hidden="until-found" as a regular hidden attribute (essentially display: none).
The experience doesn't break; it just functions the way it always has. Chromium users get the "superpower" of searching through your accordions, and everyone else gets the standard experience until their browser catches up.
A Practical Accordion Example
Here is how you might structure a modern, searchable accordion:
<div class="accordion">
<button id="btn-1" aria-controls="content-1" aria-expanded="false">
What is your return policy?
</button>
<div
id="content-1"
hidden="until-found"
role="region"
aria-labelledby="btn-1"
>
<p>Our return policy lasts 30 days. Items must be unused and in original packaging.</p>
</div>
</div>
<script>
const content = document.getElementById('content-1');
const btn = document.getElementById('btn-1');
// Handle the browser's automatic reveal
content.addEventListener('beforematch', () => {
btn.setAttribute('aria-expanded', 'true');
});
// Handle the manual click
btn.addEventListener('click', () => {
const isExpanded = btn.getAttribute('aria-expanded') === 'true';
if (isExpanded) {
content.setAttribute('hidden', 'until-found');
btn.setAttribute('aria-expanded', 'false');
} else {
content.removeAttribute('hidden');
btn.setAttribute('aria-expanded', 'true');
}
});
</script>It’s a small change to your markup, but it’s one of those "quality of life" improvements that makes your site feel significantly more professional and user-friendly. Stop hiding your content behind a brick wall. Give it a chance to be found.


