How to Create Bootstrap Dropdowns and Collapsible Elements
Build Bootstrap 5.3 dropdowns and collapsible panels with working markup, JavaScript setup, accessibility guidance, and fixes for common errors.
In Bootstrap 5.3, a dropdown is a click-toggled contextual menu, while a collapse component shows or hides a content region. Both need Bootstrap’s JavaScript plugin. A dropdown uses a trigger with data-bs-toggle="dropdown" and a .dropdown-menu; a collapsible panel uses data-bs-toggle="collapse", a selector pointing to the target, and the target’s .collapse class.
The examples below use Bootstrap 5.3 markup. For dropdown positioning outside a navbar, include Popper; the Bootstrap bundle includes it. The official references are the Bootstrap 5.3 dropdown documentation and Bootstrap 5.3 collapse documentation.
1. Load Bootstrap CSS and JavaScript
Add Bootstrap’s stylesheet in the document head and its JavaScript bundle before the closing body tag. The bundle includes Popper, which Bootstrap uses to position dropdowns dynamically. A navbar dropdown does not require Popper for positioning, but using the bundle is a simple way to include the needed JavaScript.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap menu and panel</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<!-- Components go here -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
For production, choose and pin the Bootstrap version your project uses, and follow its official installation guidance. Avoid loading multiple Bootstrap JavaScript versions on the same page.
2. Create a dropdown menu
Put the trigger and menu inside a .dropdown wrapper. The trigger can be a button or a link; a button is a good default for an action menu. The menu contains items styled with .dropdown-item.
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button"
data-bs-toggle="dropdown" aria-expanded="false">
Choose an action
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/first">First action</a></li>
<li><a class="dropdown-item" href="/second">Second action</a></li>
</ul>
</div>
Bootstrap dropdowns open by clicking, not by hovering. The trigger’s aria-expanded starts as false; Bootstrap updates it as the menu opens and closes. Use meaningful link destinations for navigation items. For actions that change page state, use buttons rather than placeholder links.
Dropdowns in a navbar
The same toggle attribute is used inside a navbar. Keep the button within the navbar’s navigation structure and retain the menu classes:
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="/">Example</a>
<div class="navbar-nav">
<div class="nav-item dropdown">
<button class="nav-link dropdown-toggle" type="button"
data-bs-toggle="dropdown" aria-expanded="false">
Resources
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/docs">Documentation</a></li>
<li><a class="dropdown-item" href="/support">Support</a></li>
</ul>
</div>
</div>
</div>
</nav>
3. Create a collapsible content region
A collapse trigger points to the panel with data-bs-target. The selector must match the target’s ID. Give the target the .collapse class. For a trigger controlling one panel, include aria-controls and keep its initial aria-expanded value consistent with the panel’s initial state.
<button class="btn btn-primary" type="button"
data-bs-toggle="collapse" data-bs-target="#details"
aria-expanded="false" aria-controls="details">
Show details
</button>
<div class="collapse" id="details">
<div class="card card-body">
Details go here.
</div>
</div>
To start with the panel open, add show to the target and change the trigger’s initial aria-expanded to true:
<button class="btn btn-primary" type="button"
data-bs-toggle="collapse" data-bs-target="#details"
aria-expanded="true" aria-controls="details">
Hide details
</button>
<div class="collapse show" id="details">
<div class="card card-body">Details go here.</div>
</div>
Bootstrap changes the expanded state as the panel opens and closes. Put padding on an inner wrapper such as the card above, rather than directly on the animated .collapse element.
One trigger for multiple panels
A selector can target more than one collapse element. In that case, aria-controls is less useful because it is intended to identify a controlled element; prefer separate triggers when each panel needs an independently understandable control.
<button class="btn btn-primary" type="button"
data-bs-toggle="collapse" data-bs-target=".more-details"
aria-expanded="false">
Toggle details
</button>
<div class="collapse more-details" id="detail-one">First panel</div>
<div class="collapse more-details" id="detail-two">Second panel</div>
4. Build an accordion-style group
Use data-bs-parent when opening one panel should close another panel in the same group. Each trigger still targets its own panel. This provides the coordinated show-and-hide behavior, but Bootstrap’s collapse plugin does not implement every optional keyboard interaction described by the ARIA Authoring Practices accordion pattern. If your interface needs that full interaction model, implement and test the missing keyboard behavior yourself.
<div id="faq-group">
<h3>
<button class="btn btn-link" type="button"
data-bs-toggle="collapse" data-bs-target="#faq-one"
aria-expanded="false" aria-controls="faq-one">
What does this section do?
</button>
</h3>
<div id="faq-one" class="collapse" data-bs-parent="#faq-group">
<div class="p-3">It reveals one answer at a time.</div>
</div>
<h3>
<button class="btn btn-link" type="button"
data-bs-toggle="collapse" data-bs-target="#faq-two"
aria-expanded="false" aria-controls="faq-two">
Can another answer open?
</button>
</h3>
<div id="faq-two" class="collapse" data-bs-parent="#faq-group">
<div class="p-3">Yes. Opening it closes the other panel.</div>
</div>
</div>
5. Initialize and control components with JavaScript
Data attributes are enough for the common click-to-toggle behavior. Use the JavaScript API when initialization or control must happen in your own code. Ensure the Bootstrap bundle is loaded before this code runs.
const dropdownElement = document.querySelector('.dropdown-toggle');
const dropdown = bootstrap.Dropdown.getOrCreateInstance(dropdownElement);
dropdown.show();
// dropdown.hide();
// dropdown.toggle();
const panelElement = document.querySelector('#details');
const panel = bootstrap.Collapse.getOrCreateInstance(panelElement, {
toggle: false
});
panel.show();
// panel.hide();
// panel.toggle();
For a collapse component, toggle: false prevents initialization from immediately changing its state. Choose either data attributes or deliberate JavaScript control for a given interaction, and avoid attaching duplicate click handlers that toggle the same component twice.
6. Choose the right component and options
| Need | Use | Key wiring |
|---|---|---|
| Show contextual links or actions | Dropdown | data-bs-toggle="dropdown" and .dropdown-menu |
| Reveal an arbitrary content region | Collapse | data-bs-toggle="collapse", a target selector, and .collapse |
| Allow only one panel in a group open | Collapse with parent | data-bs-parent="#group-id" |
Dropdowns support placement and alignment classes such as .dropup, .dropend, .dropstart, and .dropdown-menu-end. Dynamic placement uses Popper outside navbars. For specialized cases, Bootstrap documents options including auto-close behavior and offset; use the version-specific documentation when setting these through data attributes or JavaScript.
Collapse’s core choices are its initial state, target selector, and optional parent grouping. The transition respects the user’s prefers-reduced-motion setting through Bootstrap’s styling. If the content is essential, ensure it remains available when JavaScript fails or provide an appropriate progressive-enhancement strategy for the application.
7. Accessibility and interaction details
- Use a real button for a control that opens or closes content; provide visible text that describes its effect.
- For a single collapse target, connect trigger and panel with matching
aria-controlsand target ID. Setaria-expandedto match the starting state. - Use links for navigation and buttons for actions inside dropdown menus. Choose ARIA roles based on the actual content and interaction; a dropdown is not automatically an application menu widget.
- Bootstrap provides common dropdown keyboard behavior, including cursor-key movement among dropdown items and Escape to close. Check the behavior in the context of your page and do not assume Bootstrap supplies every interaction pattern for every menu type.
- Do not make hover the only way to open a dropdown. Bootstrap’s documented dropdown interaction is click toggling.
- Check focus visibility, contrast, and the reading order of the revealed content in your own theme.
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Clicking a dropdown does nothing | Bootstrap JavaScript is missing, failed to load, or is the wrong version. | Load the Bootstrap 5.3 JavaScript bundle and check the browser console and network panel for script errors. |
| Dropdown opens in the wrong place or is clipped | Popper is missing where dynamic positioning is needed, or an ancestor’s overflow styles clip the menu. | Use bootstrap.bundle outside navbar positioning cases and inspect ancestor positioning and overflow rules. |
| Bootstrap 5 markup does not respond | The markup uses Bootstrap 4’s data-toggle attribute. |
Use Bootstrap 5’s data-bs-toggle and data-bs-target attributes. |
| Collapse trigger does nothing | The target selector does not match the panel ID, or the panel lacks .collapse. |
Make the selector and ID identical, for example data-bs-target="#details" with id="details", and add the class. |
| Panel starts open but accessibility state says closed | The target has .show but the trigger says aria-expanded="false". |
Set the initial state consistently: open means .show and aria-expanded="true". |
| Collapse animation jumps or behaves oddly | Padding is applied to the animated .collapse element. |
Move padding to an inner wrapper. |
| Menu only works with a mouse hover | A custom hover handler replaced or conflicts with the documented click toggle. | Use Bootstrap’s click behavior and ensure the trigger is keyboard operable. |
| Component toggles twice or immediately closes | Both Bootstrap’s data API and a custom click handler are toggling it, or duplicate scripts are loaded. | Remove duplicate initialization and verify that only one handler controls the interaction. |
9. Performance, reliability, and cost
Dropdowns and collapse panels are client-side UI components; their visible behavior depends on Bootstrap’s JavaScript being available and initialized. Keep the page to one compatible Bootstrap CSS and JavaScript version, and avoid unnecessary custom handlers. Collapse transitions animate the panel, so keep large or expensive work out of repeated click handlers.
The code in this guide uses the public jsDelivr CDN example. For production, follow your project’s asset policy, pin the framework version, and consider how assets are delivered and cached in your deployment. The components themselves do not require a paid service; costs depend on how your project hosts its assets and application.
10. Or skip the browser setup
If you need a screenshot of the finished dropdown or collapsible panel for a pull request, documentation page, or visual review, ScreenshotNeo can capture a URL with one GET request. See the ScreenshotNeo API documentation for parameters and formats.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
- Cookie banners are accepted and removed before the shot; known consent platforms, newsletter popups, and chat widgets can be removed.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers say the page verdict and billing status.
- An MCP server provides screenshot tools for AI agents, including Claude, Cursor, and other MCP clients.
- The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
11. FAQ
Can a Bootstrap dropdown open on hover?
Bootstrap documents dropdowns as click-toggled. A custom hover interaction requires your own code and should preserve keyboard access.
Can a collapse panel start open?
Yes. Add show to the panel and initialize the trigger with aria-expanded="true".
Does a dropdown need Popper?
Popper is used for dynamic positioning outside navbars. Bootstrap’s bundle includes it, which is convenient when using dropdowns in those contexts.
Does collapse automatically create a fully accessible accordion?
No. data-bs-parent coordinates which panel is open, but Bootstrap does not include every optional keyboard interaction in the ARIA accordion pattern.


