Skip to content

Documentation

On this page

Accordion

Vertically collapsing accordions using <details> and <summary> — no Collapse plugin.

Sizes are minified and gzip. A plugin figure includes the Bootstrap runtime that plugin imports. Shipping every plugin is bootstrap.bundle.min.js at 23.3 KB gzip, not the sum of these rows.
What runs it JavaScript
Bootstrap 5.3 Collapse plugin. Accordion is that plugin; there is no accordion.js. 5.6 KB gzip
This repo details and summary, with name for an exclusive group 0 KB
Markup this component accepts. The full inventory is /components.json.
Optional <pe-focus-group> · src/behaviors/focus-group.js . Arrow, Home, and End keys across the summaries. Tab works without it.
Avoid
  • .accordion-button has to be the <summary>, a direct child of the <details>.
  • No data-bs-toggle. Opening state is the open attribute.
  • Do not put hidden or hidden="until-found" on .accordion-body. An open item would stay hidden. Accordion panels are <details>; hidden="until-found" is for custom regions.

How it works

Each item is a details.accordion-item with a summary.accordion-button. The same name on every item makes the group exclusive (replaces data-bs-parent). Add open to start expanded (replaces .show / omitting .collapsed).

The browser fires a toggle event on <details> when the open state changes.

The panel is ::details-content, and its height transitions there instead of from JavaScript. Animating block-size from 0 to auto needs interpolate-size: allow-keywords, which only Chromium has. Firefox and Safari open and close the item without the transition.

Closed panels stay in the document, so Find in page can match them (try quetzalcoatlus in the first example). Do not put hidden or display: none on .accordion-body. For a custom hidden region that is not a <details> panel, use hidden="until-found" and keep padding on an inner wrapper. Bootstrap’s reboot would otherwise force display: none and break that attribute.

Example

Click the accordions below to expand/collapse the accordion content.

To render an accordion that’s expanded by default, add the open attribute on the <details> element.

Accordion Item #1
This is the first item’s accordion body. It is shown by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.
Accordion Item #2
This is the second item’s accordion body. It is hidden by default. Find in page can still match this panel: the token is quetzalcoatlus.
Accordion Item #3
This is the third item’s accordion body. It is hidden by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.
HTML
<div class="accordion">
  <details class="accordion-item" name="accordionExample" open>
    <summary class="accordion-button">Accordion Item #1</summary>
    <div class="accordion-body">
      <strong>This is the first item’s accordion body.</strong> It is shown by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
    </div>
  </details>
  <details class="accordion-item" name="accordionExample">
    <summary class="accordion-button">Accordion Item #2</summary>
    <div class="accordion-body">
      <strong>This is the second item’s accordion body.</strong> It is hidden by default. Find in page can still match this panel: the token is <strong>quetzalcoatlus</strong>.
    </div>
  </details>
  <details class="accordion-item" name="accordionExample">
    <summary class="accordion-button">Accordion Item #3</summary>
    <div class="accordion-body">
      <strong>This is the third item’s accordion body.</strong> It is hidden by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
    </div>
  </details>
</div>

Flush

Add .accordion-flush to remove some borders and rounded corners to render accordions edge-to-edge with their parent container.

Accordion Item #1
Placeholder content for this accordion, which is intended to demonstrate the .accordion-flush class. This is the first item’s accordion body.
Accordion Item #2
Placeholder content for this accordion, which is intended to demonstrate the .accordion-flush class. This is the second item’s accordion body. Let’s imagine this being filled with some actual content.
Accordion Item #3
Placeholder content for this accordion, which is intended to demonstrate the .accordion-flush class. This is the third item’s accordion body. Nothing more exciting happening here in terms of content, but just filling up the space to make it look, at least at first glance, a bit more representative of how this would look in a real-world application.
HTML
<div class="accordion accordion-flush">
  <details class="accordion-item" name="accordionFlushExample">
    <summary class="accordion-button">Accordion Item #1</summary>
    <div class="accordion-body">Placeholder content for this accordion, which is intended to demonstrate the <code>.accordion-flush</code> class. This is the first item’s accordion body.</div>
  </details>
  <details class="accordion-item" name="accordionFlushExample">
    <summary class="accordion-button">Accordion Item #2</summary>
    <div class="accordion-body">Placeholder content for this accordion, which is intended to demonstrate the <code>.accordion-flush</code> class. This is the second item’s accordion body. Let’s imagine this being filled with some actual content.</div>
  </details>
  <details class="accordion-item" name="accordionFlushExample">
    <summary class="accordion-button">Accordion Item #3</summary>
    <div class="accordion-body">Placeholder content for this accordion, which is intended to demonstrate the <code>.accordion-flush</code> class. This is the third item’s accordion body. Nothing more exciting happening here in terms of content, but just filling up the space to make it look, at least at first glance, a bit more representative of how this would look in a real-world application.</div>
  </details>
</div>

Always open

Omit the name attribute on each details element to make accordion items stay open when another item is opened.

Accordion Item #1
This is the first item’s accordion body. It is shown by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.
Accordion Item #2
This is the second item’s accordion body. It is hidden by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.
Accordion Item #3
This is the third item’s accordion body. It is hidden by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.
HTML
<div class="accordion">
  <details class="accordion-item" open>
    <summary class="accordion-button">Accordion Item #1</summary>
    <div class="accordion-body">
      <strong>This is the first item’s accordion body.</strong> It is shown by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
    </div>
  </details>
  <details class="accordion-item">
    <summary class="accordion-button">Accordion Item #2</summary>
    <div class="accordion-body">
      <strong>This is the second item’s accordion body.</strong> It is hidden by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
    </div>
  </details>
  <details class="accordion-item">
    <summary class="accordion-button">Accordion Item #3</summary>
    <div class="accordion-body">
      <strong>This is the third item’s accordion body.</strong> It is hidden by default. You can modify any of this with custom CSS or overriding our default variables. It’s also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
    </div>
  </details>
</div>

Find in page

hidden="until-found" hides a custom region until Find in page matches it. Accordion items themselves stay on details — do not put hidden on .accordion-body.

Search this page for thylacine.

HTML
<p>Search this page for <strong>thylacine</strong>.</p>
<div hidden="until-found">
  <div class="accordion-body border rounded">
    Find in page revealed this region. The token is <strong>thylacine</strong>.
  </div>
</div>

Accessibility

<details> / <summary> is a disclosure. The browser exposes expanded and collapsed; do not add aria-expanded on the summary.

Do not put a heading inside <summary>. Screen-reader heading lists skip that text.

Tab reaches every summary without script. Optional <pe-focus-group> adds Arrow, Home, and End. Enter and Space still open the item.

Closed panels stay in the document. Find in page can match them. Do not add display: none on the body.

Browser support

Three columns, not one baseline. The same row is on the overview.
No script Polyfill No fallback
details / summary. Exclusive name: Chrome 120+, Firefox 130+, Safari 17.2+. None The height transition needs interpolate-size: allow-keywords to animate block-size from 0 to auto. That is Chromium-only (Chrome 129+), so Firefox and Safari snap the panel open. ::details-content itself is Chrome 131+, Firefox 143+, Safari 18.4+, and only styles the panel.

Arrow keys

Tab still moves through each <summary> when no extra script is loaded. Arrow keys, Home, and End are optional. Wrap the accordion in <pe-focus-group> with items="summary" and orientation="vertical", and load src/behaviors/focus-group.js. Without that module the element is only a wrapper: the items still open, and Tab still reaches every summary.

Up focuses the previous summary. Down focuses the next. Home and End jump to the ends. Focusing a summary does not open it; Enter and Space still do. The shared name keeps the group exclusive. Keys inside the panel stay there: the text field, the link, and the menu without its own focus group. The menu wrapped in a nested <pe-focus-group> handles its own arrow keys.

Focus group

The open panel has a text field, a link, and two menus. Only the menu wrapped in pe-focus-group moves with arrow keys. The accordion group moves between summaries.

Accordion Item #1

A link in the panel. Arrow keys here do not move between summaries.

Accordion Item #2
This is the second item’s accordion body. The shared name still keeps only one item open.
Accordion Item #3
This is the third item’s accordion body. Home and End jump to the first and last summary.
HTML
<script type="module" src="./node_modules/bootstrap-html/src/behaviors/focus-group.js"></script>

<pe-focus-group items="summary" orientation="vertical">
  <div class="accordion">
    <details class="accordion-item" name="accordionFocusGroup" open>
      <summary class="accordion-button">Accordion Item #1</summary>
      <div class="accordion-body">
        <div class="mb-3">
          <label class="form-label" for="accordionFocusNote">Note</label>
          <input class="form-control" id="accordionFocusNote" type="text" value="Arrow keys stay in this field">
        </div>
        <p><a href="#focus-group">A link in the panel</a>. Arrow keys here do not move between summaries.</p>
        <div class="d-flex flex-wrap gap-2">
          <div class="dropdown">
            <button class="btn btn-secondary dropdown-toggle" type="button" command="toggle-popover" commandfor="accordionMenuPlain">
              Menu without focus group
            </button>
            <ul class="dropdown-menu" popover="auto" id="accordionMenuPlain">
              <li><a class="dropdown-item" href="#focus-group">Action</a></li>
              <li><a class="dropdown-item" href="#focus-group">Another action</a></li>
            </ul>
          </div>
          <pe-focus-group items=".dropdown-item:not(.disabled, [aria-disabled='true'])">
            <div class="dropdown">
              <button class="btn btn-secondary dropdown-toggle" type="button" command="toggle-popover" commandfor="accordionMenuGrouped">
                Menu with focus group
              </button>
              <ul class="dropdown-menu" popover="auto" id="accordionMenuGrouped">
                <li><a class="dropdown-item" href="#focus-group">Action</a></li>
                <li><a class="dropdown-item" href="#focus-group">Another action</a></li>
              </ul>
            </div>
          </pe-focus-group>
        </div>
      </div>
    </details>
    <details class="accordion-item" name="accordionFocusGroup">
      <summary class="accordion-button">Accordion Item #2</summary>
      <div class="accordion-body">
        <strong>This is the second item’s accordion body.</strong> The shared <code>name</code> still keeps only one item open.
      </div>
    </details>
    <details class="accordion-item" name="accordionFocusGroup">
      <summary class="accordion-button">Accordion Item #3</summary>
      <div class="accordion-body">
        <strong>This is the third item’s accordion body.</strong> Home and End jump to the first and last summary.
      </div>
    </details>
  </div>
</pe-focus-group>