Bootstrap 5 Notification Dropdown
A notification dropdown is a navbar-integrated panel that reveals a scrollable list of user alerts, messages, or system events when a bell icon is clicked. It is composed from Bootstrap 5's Dropdown plugin, Badge utility, List Group, and Flexbox utilities, no custom component exists in the official Bootstrap distribution. Use it in admin dashboards, SaaS applications, or any authenticated interface where users need real-time or recent activity at a glance.
Bootstrap class
.dropdown, .dropdown-menu, .badgeCommon use cases
- An e-commerce admin panel shows order status changes (new orders, payment failures, and shipment updates) as individual notification items inside the dropdown.
- A project management tool surfaces @mention alerts and task assignment notifications so team members can respond without leaving their current page.
- A hospital staff portal displays urgent patient alerts and ward announcements with colour-coded badges distinguishing critical from informational notices.
- A SaaS billing dashboard notifies account owners of upcoming renewal dates, failed card charges, and usage limit warnings via timestamped dropdown entries.
Variants and classes
| Variant | Description and classes |
|---|---|
| Basic Unread Badge | Bell icon button with a red badge counter and a plain dropdown list of notification items using list-group-flush inside the dropdown menu.dropdown btn p-0 badge bg-danger list-group list-group-flush dropdown-menu |
| Grouped with Section Headers | Notification items divided into Today and Earlier sections using small muted dropdown headers, keeping recent activity visually distinct.dropdown-menu dropdown-header text-muted small list-group-item d-flex gap-3 |
| Scrollable Panel with Footer Action | A fixed-height scrollable list constrained with overflow-y-auto and a sticky footer link that marks all notifications as read or navigates to a full notifications page.dropdown-menu overflow-y-auto list-group list-group-flush border-top mt-2 |
| Inline Avatar + Meta | Each notification row pairs a user avatar thumbnail with the event description and a relative timestamp, using flex utilities to align content horizontally.d-flex align-items-start gap-3 py-2 px-3 list-group-item list-group-item-action |
Code example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Notification Dropdown</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<style>
.notification-menu {
width: 360px;
max-height: 480px;
overflow-y: auto;
}
.notif-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
.list-group-item-action:focus {
outline: 2px solid #0d6efd;
outline-offset: -2px;
}
</style>
</head>
<body class="bg-light">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark px-4">
<a class="navbar-brand" href="#">MyApp</a>
<div class="ms-auto d-flex align-items-center gap-3">
<!-- Notification Dropdown -->
<div class="dropdown">
<button
class="btn btn-dark p-1 position-relative"
type="button"
id="notifDropdown"
data-bs-toggle="dropdown"
aria-expanded="false"
aria-label="Notifications (4 unread)"
>
<i class="bi bi-bell fs-5 text-white"></i>
<span
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger"
aria-label="4 unread notifications"
>4</span>
</button>
<div
class="dropdown-menu dropdown-menu-end shadow notification-menu p-0"
aria-labelledby="notifDropdown"
>
<!-- Header -->
<div class="d-flex align-items-center justify-content-between px-3 py-2 border-bottom">
<span class="fw-semibold">Notifications</span>
<button class="btn btn-link btn-sm text-decoration-none p-0 text-muted" type="button">Mark all read</button>
</div>
<!-- Section label -->
<p class="dropdown-header text-uppercase text-muted small mb-0 pt-2">Today</p>
<!-- Unread item 1 -->
<a href="#" class="list-group-item list-group-item-action d-flex align-items-start gap-3 px-3 py-2 border-0">
<img src="https://i.pravatar.cc/36?img=12" alt="" width="36" height="36" class="rounded-circle flex-shrink-0 mt-1">
<div class="flex-grow-1 overflow-hidden">
<p class="mb-0 text-truncate"><strong>Sarah Connor</strong> assigned you a task in <em>Project Atlas</em>.</p>
<small class="text-muted">2 minutes ago</small>
</div>
<span class="notif-dot bg-primary mt-2" aria-label="Unread"></span>
</a>
<!-- Unread item 2 -->
<a href="#" class="list-group-item list-group-item-action d-flex align-items-start gap-3 px-3 py-2 border-0">
<div class="flex-shrink-0 mt-1 d-flex align-items-center justify-content-center bg-warning-subtle rounded-circle" style="width:36px;height:36px">
<i class="bi bi-credit-card text-warning"></i>
</div>
<div class="flex-grow-1 overflow-hidden">
<p class="mb-0 text-truncate">Payment of <strong>£349.00</strong> failed: update your card details.</p>
<small class="text-muted">15 minutes ago</small>
</div>
<span class="notif-dot bg-primary mt-2" aria-label="Unread"></span>
</a>
<!-- Unread item 3 -->
<a href="#" class="list-group-item list-group-item-action d-flex align-items-start gap-3 px-3 py-2 border-0">
<div class="flex-shrink-0 mt-1 d-flex align-items-center justify-content-center bg-success-subtle rounded-circle" style="width:36px;height:36px">
<i class="bi bi-box-seam text-success"></i>
</div>
<div class="flex-grow-1 overflow-hidden">
<p class="mb-0 text-truncate">Order <strong>#ORD-8821</strong> has been shipped.</p>
<small class="text-muted">1 hour ago</small>
</div>
<span class="notif-dot bg-primary mt-2" aria-label="Unread"></span>
</a>
<!-- Section label -->
<p class="dropdown-header text-uppercase text-muted small mb-0 pt-2">Earlier</p>
<!-- Read item -->
<a href="#" class="list-group-item list-group-item-action d-flex align-items-start gap-3 px-3 py-2 border-0 opacity-75">
<img src="https://i.pravatar.cc/36?img=7" alt="" width="36" height="36" class="rounded-circle flex-shrink-0 mt-1">
<div class="flex-grow-1 overflow-hidden">
<p class="mb-0 text-truncate"><strong>James Briggs</strong> commented on your report.</p>
<small class="text-muted">Yesterday, 4:52 pm</small>
</div>
</a>
<!-- Read item -->
<a href="#" class="list-group-item list-group-item-action d-flex align-items-start gap-3 px-3 py-2 border-0 opacity-75">
<div class="flex-shrink-0 mt-1 d-flex align-items-center justify-content-center bg-danger-subtle rounded-circle" style="width:36px;height:36px">
<i class="bi bi-exclamation-triangle text-danger"></i>
</div>
<div class="flex-grow-1 overflow-hidden">
<p class="mb-0 text-truncate">Server CPU usage exceeded 90% threshold.</p>
<small class="text-muted">2 days ago</small>
</div>
</a>
<!-- Footer -->
<div class="border-top text-center">
<a href="/notifications" class="btn btn-link btn-sm w-100 py-2 text-decoration-none">View all notifications</a>
</div>
</div>
</div>
<!-- Profile -->
<img src="https://i.pravatar.cc/36?img=3" alt="Profile" width="36" height="36" class="rounded-circle">
</div>
</nav>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>Live examples
Minimal Bell with Badge Count
The smallest viable implementation: a bell button with a danger badge counter that toggles a plain dropdown menu. No avatars or sections, suitable for simple utility dashboards.
Scrollable Notifications with Icon Avatars
A fixed-height scrollable list using overflow-y-auto constrained to 320 px. Each entry uses a coloured icon inside a circle as the avatar, suitable when user photos are unavailable.
Empty State Notification Dropdown
Handles the zero-notification case gracefully with a centred icon and message inside the dropdown menu. Prevents a jarring blank panel when the user has cleared all alerts.
Canvas template variants
Canvas Builder builds pages on the Canvas HTML template, which adds its own styled versions of Bootstrap 5 components. Variants you can ask for in a prompt:
- Bell icon notification dropdown with unread badge counter generated from a prompt
- Scrollable admin notification panel with avatar rows and section headers
- Dark navbar notification dropdown with colour-coded system alert icons
- E-commerce order update notification dropdown with timestamped list items
- Canvas Builder prompt: notification dropdown with mark-all-read footer action
Best practices
Set a max-height and overflow-y on the menu
Without a constrained height, a long notification list will overflow the viewport on smaller screens. Apply a custom max-height (e.g. 400 to 480 px) and overflow-y: auto directly on the dropdown-menu element or a wrapper div inside it. Do not rely on Bootstrap's default dropdown sizing for this pattern.
Use aria-label and aria-live for accessibility
The trigger button should carry an aria-label that includes the unread count (e.g. 'Notifications, 4 unread') so screen-reader users know at a glance. When new notifications arrive dynamically, wrap the badge in a span with role='status' and aria-live='polite' so assistive technologies announce the updated count without interrupting the user.
Prevent dropdown close on internal clicks
If you add interactive controls inside the panel, such as a 'Mark all read' button, Bootstrap will close the dropdown on any click inside it by default. Stop this by calling event.stopPropagation() on the button's click handler, or add data-bs-auto-close='outside' to the toggle button so the menu only closes when the user clicks outside it.
Keep the badge hidden when count is zero
Use Bootstrap's d-none utility class toggled via JavaScript to hide the badge entirely when there are no unread notifications, rather than displaying a zero. A visible zero badge can cause confusion and erodes trust in the component's accuracy.