Show/Hide & Expand
Disclosure
AvailableThe simplest show/hide pattern, like a "show more" toggle that reveals or hides a single section.
What Is a Disclosure (Show/Hide)?
A disclosure is the simplest show/hide UI: pressing a single button toggles a single content region open or closed. It is commonly used for "Show more," "View details," and "FAQ answer" interactions.
While an accordion groups multiple heading-panel pairs together, a disclosure is the minimal unit — one button, one region.
Why Does Accessibility Matter?
If you only style the appearance, the following users are left behind.
- People who navigate with the keyboard only. If the trigger is a
<div>, it cannot receive focus via Tab, making it impossible to open at all. - Screen reader users. A plain
<div>is not recognized as an interactive control, and there is no indication of whether the region is currently open or closed.
The fix is straightforward: use a <button> for the trigger and communicate the open/closed state with aria-expanded.
Live Demo (Recommended Implementation)
The "Show more" button below follows the APG pattern. Try operating it with the keyboard only, without using a mouse.
Accessibility is the practice of ensuring that everyone can access information and services, regardless of age or disability.
On the web, WCAG (Web Content Accessibility Guidelines) is the internationally recognized standard. It covers keyboard operability, color contrast, screen reader support, and more, and is a legal requirement for public-sector websites in many countries.
Try it: Tab to the button → press Enter or Space to toggle. The label switches between "Show more" and "Hide".
Tip
Turn on a screen reader (on macOS, press ⌘+F5 for VoiceOver) and focus the button. You will hear something like "Show more, collapsed, button" — the role and state are announced. This is the effect of aria-expanded.
Keyboard Interaction
| Key | Action | Priority |
|---|---|---|
| Enter / Space | Open / close the content region | Required |
| Tab | Move focus to the next / previous focusable element | Required |
Note
Toggling with Enter and Space comes automatically when you use a <button> as the trigger. There is no need to write your own key handlers. This is the power of native elements.
Required WAI-ARIA Roles & Properties
| Target | Attribute / Role | Meaning |
|---|---|---|
| Trigger | <button type="button"> | Makes the element interactive. Provides focus, Enter/Space activation, and the button role automatically. |
| Trigger | aria-expanded="true | false" | Indicates whether the controlled region is open. Must be updated on every state change. |
| Trigger | aria-controls="region-id" | Identifies which content region this button controls. |
| Closed region | hidden | Hides the region from the DOM when closed, removing it from keyboard navigation and screen reader output. |
Recommended Pattern (Good)
Good / Recommended
Use a <button> for the trigger and keep aria-expanded in sync with the visible state.
Markup:
<button type="button"
id="more-btn"
aria-expanded="false"
aria-controls="more-region">
Show more
</button>
<div id="more-region" hidden>
<p>Here is the detailed explanation that was hidden.</p>
</div>Toggle script (state synchronization is all you need):
const trigger = document.getElementById('more-btn');
const region = document.getElementById('more-region');
if (trigger && region) {
trigger.addEventListener('click', () => {
const expanded = trigger.getAttribute('aria-expanded') === 'true';
// Toggle state and sync aria-expanded, visibility, and label
trigger.setAttribute('aria-expanded', String(!expanded));
region.hidden = expanded;
trigger.textContent = expanded ? 'Show more' : 'Hide';
});
}Note
Switching the button label between "Show more" and "Hide" also helps sighted users understand what the next action will do. Make sure to always update aria-expanded — changing only the visual label does not communicate the state to assistive technology.
Anti-pattern (Bad)
Below is a "visually identical" toggle built with a <div> and onclick.It works with a mouse, but is completely inoperable with the keyboard.Try pressing Tab → Enter and compare the difference with the demo above.
Accessibility is the practice of ensuring that everyone can access information and services, regardless of age or disability.
On the web, WCAG is the internationally recognized standard. It covers keyboard operability, color contrast, screen reader support, and more.
Try it: pressing Tab does not move focus to "Show more". A screen reader does not recognize it as a button, and there is no indication that it can be toggled.
<!-- ❌ Anti-pattern -->
<!-- A div cannot receive keyboard focus and is not recognized as a button -->
<div class="more" onclick="toggle()">Show more +</div>
<div id="more" style="display:none">
<p>Here is the detailed explanation that was hidden.</p>
</div>Bad / Avoid
Problems with this implementation:
- Cannot be operated with the keyboard — a
divcannot receive focus. - Role is not communicated — to a screen reader it sounds like plain text, not a control you can press.
- State is not communicated — without
aria-expanded, open/closed cannot be determined. - Relies on inline
display:nonestyles instead of thehiddenattribute or proper state management.
Tip
If you must use a <div>, you need to add role="button", tabindex="0",Enter/Space key handlers, and aria-expanded — all by hand. Starting with a <button> gives you most of that for free.
Implementation Checklist
- The trigger is a <button type="button"> element
- aria-expanded always matches the open/close state
- aria-controls points to the controlled region's id
- The closed region uses hidden to exclude it from keyboard and screen reader access
- The disclosure can be toggled by keyboard alone, and focus indicators are visible
- (Optional) The button label changes to reflect the current state
Source (English):Disclosure Pattern — W3C APG(opens in a new tab)