Home / Snippets / UI Components /
Button with badge
Notification count badge anchored to a button corner using absolute positioning — no JavaScript.
Quick implementation
.btn-badge {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.5rem 1.25rem;
font-size: 0.9rem;
font-family: inherit;
font-weight: 600;
background: var(--accent-bg);
color: oklch(1 0 0);
border: none;
border-radius: 0.5rem;
cursor: pointer;
transition: opacity 0.15s;
}
.btn-badge:hover { opacity: 0.85; }
.btn-badge__count {
position: absolute;
top: -0.5rem;
right: -0.5rem;
min-width: 1.25rem;
height: 1.25rem;
padding: 0 0.3rem;
background: oklch(0.62 0.22 25);
color: oklch(1 0 0);
font-size: 0.65rem;
font-weight: 700;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
pointer-events: none;
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building a notification UI component.
Goal: A button with a small count badge anchored to its top-right corner — no JavaScript.
Technical constraints:
- Use position: relative on the button wrapper and position: absolute on the badge element.
- Badge position: top: -0.5rem; right: -0.5rem to overlap the button corner.
- Use min-width equal to height and border-radius: 50% so the badge is circular for single digits and pill-shaped for double digits.
- Use oklch() for all color values — a red/danger hue for the badge (e.g., oklch(0.62 0.22 25)).
- Add pointer-events: none to the badge so it does not block clicks on the button.
- Ensure the badge text is vertically and horizontally centered using flexbox.
Framework variant (pick one):
A) Vanilla CSS with a .btn-badge wrapper class and .btn-badge__count child class.
B) React component — accept count as a prop, hide badge automatically when count is 0.
Edge cases to handle:
- Double-digit counts (e.g., 99) must not break the circular shape — use min-width not fixed width.
- Counts over 99 should display as "99+" with a pill shape instead of a circle.
- Badge must remain visible if the parent button is inside an overflow: hidden container.
Return CSS.
Why this matters in 2026
Notification badges on buttons are one of the most common UI patterns in dashboards, messaging apps, and admin panels. Getting the positioning right without JavaScript — using only position: relative and position: absolute — keeps the component dependency-free and composable. The badge must scale gracefully from 1 to 99+ without breaking the circular shape or overflowing its container.
The logic
position: relative on the button creates a positioning context so the badge's position: absolute anchors to the button corner rather than the viewport. top: -0.5rem; right: -0.5rem shifts the badge to overlap the corner precisely. Using min-width instead of a fixed width lets the badge pill outward for double-digit counts while staying circular for single digits. border-radius: 50% only produces a circle when width equals height, so the min-width: 1.25rem; height: 1.25rem constraint is essential.
Accessibility & performance
Add aria-label="N notifications" to the badge element so screen readers announce the count in context — bare numbers without labels are meaningless to assistive technology. Set pointer-events: none on the badge so it does not intercept clicks meant for the button. Ensure the red badge color (oklch(0.62 0.22 25)) achieves at least 4.5:1 contrast against the white count text, and use aria-live="polite" if the count updates dynamically.