Skip to content

The hidden Attribute

Global Attribute

The hidden attribute indicates that an element is not yet, or is no longer, relevant. Hidden elements are removed from the rendering and the accessibility tree, making them completely invisible to both visual users and assistive technologies.

<element hidden>Content</element>
<element hidden="hidden">Content</element>
<element hidden="until-found">Content</element>
ValueDescription
Boolean (no value)Element is completely hidden
"hidden"Same as boolean (explicitly hidden)
"until-found"Hidden but findable with browser’s find-in-page
Result
Result
Result
Result

The hidden attribute is implemented in browsers as:

[hidden] {
display: none !important;
}

This means:

  • Element is not rendered
  • Takes no space in layout
  • Not in accessibility tree
  • Can be overridden by CSS with higher specificity

hidden indicates irrelevance, not just invisibility:

<!-- Good: Content not currently relevant -->
<div hidden>
<p>This feature is not available in your region.</p>
</div>
<!-- Bad: Just styling (use CSS instead) -->
<div hidden>
<p>Fancy animation that will show later</p>
</div>

Semantic hiding: Content is irrelevant to current context ✓ Programmatic control: Show/hide based on application state ✓ Accessibility: Remove from accessibility tree ✓ Progressive enhancement: Works without CSS

<article>
<h2>Article Title</h2>
<p>Preview text...</p>
<div hidden>
<p>Full article content that requires login...</p>
</div>
</article>

Styling decisions: Responsive design, animations ✓ Reusable classes: .hidden, .mobile-onlyComplex selectors: :hover, :focus, media queries

/* Responsive hiding */
@media (max-width: 768px) {
.desktop-only {
display: none;
}
}
/* Interactive hiding */
.dropdown-menu {
display: none;
}
.dropdown:hover .dropdown-menu {
display: block;
}
  1. Content is hidden initially
  2. User searches with Ctrl+F (Cmd+F)
  3. Browser finds matching text
  4. Element is automatically revealed
  5. beforematch event is fired
<div hidden="until-found">
<h2>Secret Section</h2>
<p>This content is hidden but searchable!</p>
</div>
<script>
document.querySelector('[hidden="until-found"]')
.addEventListener('beforematch', (e) => {
console.log('Content revealed by search!');
// You can style the revealed content
e.target.style.borderColor = '#3b82f6';
});
</script>
  • Long documentation: Hide advanced sections
  • FAQ pages: Initially collapse answers
  • Search-optimized content: Allow users to find hidden content
  • Progressive disclosure: Show content when needed
<!-- Good: Indicates irrelevance -->
<div hidden>
<p>This feature requires Premium subscription</p>
</div>
<!-- Bad: Just for styling -->
<div hidden class="will-animate-in">
<p>Welcome message</p>
</div>
<!-- DON'T DO THIS -->
<div hidden>
<p>Admin API Key: sk_live_abc123...</p>
</div>
<button
aria-expanded="false"
aria-controls="details"
onclick="toggle()">
Show Details
</button>
<div id="details" hidden>
<p>Additional information...</p>
</div>
<script>
function toggle() {
const details = document.getElementById('details');
const button = event.target;
const isHidden = details.hasAttribute('hidden');
if (isHidden) {
details.removeAttribute('hidden');
button.setAttribute('aria-expanded', 'true');
} else {
details.hidden = true;
button.setAttribute('aria-expanded', 'false');
}
}
</script>

4. Prefer hidden Over display: none for Conditional Content

Section titled “4. Prefer hidden Over display: none for Conditional Content”
// Good: Semantic and clear
if (user.isLoggedIn) {
loginButton.hidden = true;
logoutButton.hidden = false;
}
// Also good: CSS classes
if (user.isLoggedIn) {
loginButton.classList.add('hidden');
logoutButton.classList.remove('hidden');
}

Hidden elements should not be:

  • Focusable with keyboard
  • Announced by screen readers
  • Navigable with Tab key
// Verify element is truly hidden
const el = document.getElementById('hidden-element');
console.log(el.hidden); // true
console.log(getComputedStyle(el).display); // "none"
const element = document.getElementById('myElement');
// Set hidden
element.hidden = true;
element.setAttribute('hidden', '');
element.toggleAttribute('hidden');
// Remove hidden
element.hidden = false;
element.removeAttribute('hidden');
// Check if hidden
if (element.hidden) {
console.log('Element is hidden');
}
// Set until-found
element.setAttribute('hidden', 'until-found');
// Listen for reveal
element.addEventListener('beforematch', (event) => {
console.log('Element revealed!');
// Element is automatically shown by browser
});

Hidden elements are:

  • Not announced by screen readers
  • Not in the accessibility tree
  • Not navigable with screen reader shortcuts
<!-- Not accessible to screen readers -->
<div hidden>
<button>Click me</button>
</div>

If you need to hide visually but keep accessible:

/* Visually hidden but screen reader accessible */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
<button>
<span class="sr-only">Close dialog</span>
<span aria-hidden="true">×</span>
</button>
FeatureChromeFirefoxSafariEdge
hidden (boolean)6+4+5.1+12+
hidden="until-found"102+🚫🚫102+
beforematch event102+🚫🚫102+
  • aria-hidden - Hide from screen readers only (element still visible)
  • inert - Make element non-interactive but visible
  • aria-expanded - Indicate if controlled content is expanded