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.
Primary 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 & Classes
| Variant | Description |
|---|---|
| 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. |
| Grouped with Section Headers | Notification items divided into Today and Earlier sections using small muted dropdown headers, keeping recent activity visually distinct. |
| 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. |
| 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. |
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 Framework Variants
The Canvas template extends Bootstrap 5 with 1,658+ component variants. Generate any of these using Canvas Builder:
- ✓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–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.