Show/Hide & Expand

Disclosure

Available

The 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.

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.

Accessible Disclosure

Accessibility is the practice of ensuring that everyone can access information and services, regardless of age or disability.

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

KeyActionPriority
Enter / SpaceOpen / close the content regionRequired
TabMove focus to the next / previous focusable elementRequired

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

TargetAttribute / RoleMeaning
Trigger<button type="button">Makes the element interactive. Provides focus, Enter/Space activation, and the button role automatically.
Triggeraria-expanded="true | false"Indicates whether the controlled region is open. Must be updated on every state change.
Triggeraria-controls="region-id"Identifies which content region this button controls.
Closed regionhiddenHides 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 TabEnter and compare the difference with the demo above.

Broken Disclosure Built with a div

Accessibility is the practice of ensuring that everyone can access information and services, regardless of age or disability.

Show 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 div cannot 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:none styles instead of the hidden attribute 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-expandedall by hand. Starting with a <button> gives you most of that for free.

Implementation Checklist


Source (English):Disclosure Pattern — W3C APG(opens in a new tab)