Bootstrap 5 Accordion with Plus/Minus Icons: Step-by-Step Guide

Bootstrap accordion showing an expanded panel with a minus icon and collapsed panels with plus icons.
Spread the love

To build a Bootstrap accordion with plus/minus icons, keep Bootstrap’s collapse markup and replace the default arrow with a small decorative icon. Use the button’s aria-expanded state to switch between plus and minus. Bootstrap updates that state for you, so the icon needs no separate JavaScript.

In this guide, we’ll build a two-question FAQ, add our own icons with CSS, and then look at the changes needed for an all-closed or always-open accordion. The examples use Bootstrap 5.3 and ordinary HTML, so you can use them in a landing page or an admin interface.

Step 1: Add Bootstrap to your page

For a quick local example, add this stylesheet inside your document’s <head> and the bundle before the closing </body> tag. Keep your document’s viewport meta tag so the example displays correctly on mobile. If your project already loads Bootstrap 5.3, use that installation instead of loading it twice.

<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">

<!-- Before </body> -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

The stylesheet gives us the accordion layout. The JavaScript bundle provides the collapse behaviour. This example pins a specific 5.3 release for reproducibility; it does not require jQuery or an icon library.

Step 2: Create the FAQ markup

Let’s start with one answer open and a second answer closed. Copy this markup into your page body. The small empty span is where we’ll draw the icon in the next step.

<div class="accordion faq-icons" id="projectFaq">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button" type="button"
        data-bs-toggle="collapse" data-bs-target="#faqOne"
        aria-expanded="true" aria-controls="faqOne">
        Can I customize the colours?
        <span class="faq-icon ms-auto" aria-hidden="true"></span>
      </button>
    </h2>
    <div id="faqOne" class="accordion-collapse collapse show"
      data-bs-parent="#projectFaq">
      <div class="accordion-body">Yes. Add your project styles after Bootstrap.</div>
    </div>
  </div>
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed" type="button"
        data-bs-toggle="collapse" data-bs-target="#faqTwo"
        aria-expanded="false" aria-controls="faqTwo">
        Can several answers stay open?
        <span class="faq-icon ms-auto" aria-hidden="true"></span>
      </button>
    </h2>
    <div id="faqTwo" class="accordion-collapse collapse"
      data-bs-parent="#projectFaq">
      <div class="accordion-body">Yes. Remove data-bs-parent from each panel.</div>
    </div>
  </div>
</div>

Each button points to exactly one panel: data-bs-target="#faqOne" matches id="faqOne". The first panel has show, and its button starts with aria-expanded="true". The closed button has collapsed and aria-expanded="false". Keep these three pieces consistent when choosing the initial state.

The data-bs-parent attribute makes this behave like a traditional FAQ: opening one answer closes another within the same accordion. Give every panel and accordion a unique ID if you place multiple examples on the same page.

Step 3: Replace the arrow with plus/minus icons

Add the following CSS after Bootstrap’s stylesheet. The faq-icons wrapper limits the change to this example, leaving other accordions in your project alone.

/* Load this after Bootstrap. Scope it to this accordion. */
.faq-icons .accordion-button::after { display: none; }
.faq-icon {
  position: relative;
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
}
.faq-icon::before,
.faq-icon::after {
  content: "";
  position: absolute;
  background: currentColor;
}
.faq-icon::before {
  top: calc(50% - 1px);
  left: 0;
  width: 100%;
  height: 2px;
}
.faq-icon::after {
  top: 0;
  left: calc(50% - 1px);
  width: 2px;
  height: 100%;
}
/* An open button displays only the horizontal stroke. */
.faq-icons .accordion-button[aria-expanded="true"] .faq-icon::after {
  display: none;
}

The horizontal stroke is always visible. The vertical stroke appears only while the panel is closed, giving us a plus sign. When Bootstrap changes aria-expanded to true, we hide that vertical stroke and get a minus sign. Using currentColor makes the icon follow the button text colour.

Our icon has aria-hidden="true" because it is decorative. Screen readers can already identify the expanded state from the button. We also keep a real button, so visitors can reach it with Tab and activate it with Enter or Space.

Example: Start with every answer closed

To close the first answer initially, change its button and panel together. Keep the same icon span and panel content from the full example.

<button class="accordion-button collapsed" type="button"
  data-bs-toggle="collapse" data-bs-target="#faqOne"
  aria-expanded="false" aria-controls="faqOne">
  Can I customize the colours?
  <span class="faq-icon ms-auto" aria-hidden="true"></span>
</button>

<div id="faqOne" class="accordion-collapse collapse"
  data-bs-parent="#projectFaq">
  <div class="accordion-body">Yes. Add your project styles after Bootstrap.</div>
</div>

Example: Allow several answers to stay open

Remove data-bs-parent from every panel in that accordion. The buttons, IDs and icon CSS remain the same. Each answer can then open or close independently.

<div id="faqTwo" class="accordion-collapse collapse">
  <div class="accordion-body">This answer can stay open alongside another.</div>
</div>

Common problems and how to fix them

The button does nothing: check that the Bootstrap bundle loaded, your target ID exists, and you used data-bs-toggle rather than the older data-toggle attribute. Avoid including multiple copies of Bootstrap’s JavaScript.

The plus sign shows on an open answer: check the initial show, collapsed and aria-expanded values. Don’t maintain a second click handler that toggles the icon independently of the panel.

Both an arrow and a plus sign appear: ensure our CSS comes after Bootstrap and the outer element has faq-icons. The first rule hides Bootstrap’s original arrow only inside that wrapper.

The wrong answer opens: look for duplicate IDs, especially after copying an accordion. Each aria-controls value should match the corresponding panel ID without a hash.

Check the finished accordion

Try opening the second answer, closing it again, and using Tab followed by Enter or Space. Check the icon in both states and at a narrow screen width with a long question. Preserve Bootstrap’s visible focus outline. Bootstrap does not implement every optional accordion keyboard shortcut, such as arrow-key navigation; add and test those separately if your interface requires them.

For further options, see the official Bootstrap accordion documentation. If you’re building a complete website or dashboard, explore our AppStrap Bootstrap theme. You can also read our guide to Bootstrap negative margins for more layout examples.

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *

Sign up for our Newsletter

Get the latest updates, free stuff, and more delivered right to your inbox.