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