UI Components Easy
Indicator
DaisyUI-style badge indicator — overlays a colored dot/badge on any element (button, avatar, card) for unread counts or status.
Open in Lab
MCP
css
Targets: HTML
Code
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Inter, system-ui, sans-serif;
background: #050910;
color: #f2f6ff;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.demo {
width: 100%;
max-width: 640px;
}
.demo-title {
font-size: 1.5rem;
font-weight: 800;
margin-bottom: 0.375rem;
}
.demo-sub {
color: #475569;
font-size: 0.875rem;
margin-bottom: 2rem;
}
.section {
margin-bottom: 2rem;
}
.section-label {
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #475569;
margin-bottom: 0.875rem;
}
.row {
display: flex;
flex-wrap: wrap;
gap: 1.25rem;
align-items: center;
}
.row--wrap {
align-items: flex-start;
}
/* ── Indicator wrapper ── */
.indicator {
position: relative;
display: inline-flex;
}
/* ── Badge base ── */
.indicator__badge {
position: absolute;
top: 0;
right: 0;
transform: translate(35%, -35%);
z-index: 1;
flex-shrink: 0;
}
/* ── Online dot ── */
.indicator__badge--online,
.indicator__badge--away,
.indicator__badge--offline {
width: 11px;
height: 11px;
border-radius: 50%;
border: 2px solid #050910;
}
.indicator__badge--online {
background: #22c55e;
box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3);
animation: pulse-green 2s ease-in-out infinite;
}
.indicator__badge--away {
background: #f59e0b;
}
.indicator__badge--offline {
background: #475569;
}
@keyframes pulse-green {
0%,
100% {
box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3);
}
50% {
box-shadow: 0 0 0 5px rgba(34, 197, 94, 0.0);
}
}
/* ── Count badge ── */
.indicator__badge--count {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 18px;
height: 18px;
padding: 0 4px;
border-radius: 999px;
font-size: 0.65rem;
font-weight: 700;
line-height: 1;
border: 2px solid #050910;
color: #fff;
}
/* ── Label badge ── */
.indicator__badge--label {
display: inline-flex;
align-items: center;
padding: 0.2rem 0.5rem;
border-radius: 999px;
font-size: 0.65rem;
font-weight: 700;
line-height: 1;
border: 2px solid #050910;
color: #fff;
white-space: nowrap;
transform: translate(25%, -40%);
}
/* ── Alert dot ── */
.indicator__badge--dot {
width: 9px;
height: 9px;
border-radius: 50%;
border: 2px solid #050910;
}
/* ── Color modifiers ── */
.indicator__badge--red {
background: #ef4444;
}
.indicator__badge--blue {
background: #3b82f6;
}
.indicator__badge--green {
background: #22c55e;
}
.indicator__badge--amber {
background: #f59e0b;
}
.indicator__badge--purple {
background: #a78bfa;
}
/* ── Avatar ── */
.avatar {
width: 44px;
height: 44px;
border-radius: 50%;
background: linear-gradient(135deg, #3b82f6, #2563eb);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
font-weight: 700;
color: #fff;
user-select: none;
}
.avatar--purple {
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
}
.avatar--slate {
background: linear-gradient(135deg, #475569, #334155);
}
/* ── Button ── */
.btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.55rem 1rem;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.05);
color: #cbd5e1;
font-family: inherit;
font-size: 0.85rem;
font-weight: 500;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.btn:hover {
background: rgba(255, 255, 255, 0.09);
border-color: rgba(255, 255, 255, 0.18);
}
/* ── Icon button ── */
.icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.05);
color: #94a3b8;
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.icon-btn:hover {
background: rgba(255, 255, 255, 0.09);
color: #f2f6ff;
}
/* ── Card ── */
.card {
padding: 0.875rem 1rem;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.08);
background: #0a1120;
min-width: 180px;
}
.card-name {
font-size: 0.875rem;
font-weight: 600;
color: #f2f6ff;
margin-bottom: 0.25rem;
}
.card-desc {
font-size: 0.75rem;
color: #475569;
}<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Indicator</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="demo">
<h1 class="demo-title">Indicator</h1>
<p class="demo-sub">Overlay badges and status dots on any element.</p>
<section class="section">
<p class="section-label">Avatar — online presence</p>
<div class="row">
<!-- Online -->
<div class="indicator" aria-label="User avatar, online">
<div class="avatar">JD</div>
<span class="indicator__badge indicator__badge--online" aria-hidden="true"></span>
</div>
<!-- Away -->
<div class="indicator" aria-label="User avatar, away">
<div class="avatar avatar--purple">KL</div>
<span class="indicator__badge indicator__badge--away" aria-hidden="true"></span>
</div>
<!-- Offline -->
<div class="indicator" aria-label="User avatar, offline">
<div class="avatar avatar--slate">MR</div>
<span class="indicator__badge indicator__badge--offline" aria-hidden="true"></span>
</div>
</div>
</section>
<section class="section">
<p class="section-label">Button — unread count</p>
<div class="row">
<div class="indicator">
<button class="btn" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/>
<path d="M13.73 21a2 2 0 0 1-3.46 0"/>
</svg>
Notifications
</button>
<span class="indicator__badge indicator__badge--count indicator__badge--red" aria-label="4 unread notifications">4</span>
</div>
<div class="indicator">
<button class="btn" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
Messages
</button>
<span class="indicator__badge indicator__badge--count indicator__badge--blue" aria-label="12 unread messages">12</span>
</div>
<div class="indicator">
<button class="btn" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>
</svg>
Cart
</button>
<span class="indicator__badge indicator__badge--count indicator__badge--green" aria-label="3 items in cart">3</span>
</div>
</div>
</section>
<section class="section">
<p class="section-label">Card — status label</p>
<div class="row row--wrap">
<div class="indicator">
<div class="card">
<p class="card-name">Production API</p>
<p class="card-desc">api.example.com · us-east-1</p>
</div>
<span class="indicator__badge indicator__badge--label indicator__badge--green" aria-label="Status: live">Live</span>
</div>
<div class="indicator">
<div class="card">
<p class="card-name">Staging API</p>
<p class="card-desc">staging.example.com · eu-west-1</p>
</div>
<span class="indicator__badge indicator__badge--label indicator__badge--amber" aria-label="Status: beta">Beta</span>
</div>
<div class="indicator">
<div class="card">
<p class="card-name">Legacy Service</p>
<p class="card-desc">legacy.example.com · deprecated</p>
</div>
<span class="indicator__badge indicator__badge--label indicator__badge--red" aria-label="Status: error">Error</span>
</div>
</div>
</section>
<section class="section">
<p class="section-label">Icon — alert dot</p>
<div class="row">
<div class="indicator">
<button class="icon-btn" type="button" aria-label="Inbox with unread items">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/>
<path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/>
</svg>
</button>
<span class="indicator__badge indicator__badge--dot indicator__badge--red" aria-hidden="true"></span>
</div>
<div class="indicator">
<button class="icon-btn" type="button" aria-label="Settings with pending update">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="12" cy="12" r="3"/>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
</svg>
</button>
<span class="indicator__badge indicator__badge--dot indicator__badge--blue" aria-hidden="true"></span>
</div>
<div class="indicator">
<button class="icon-btn" type="button" aria-label="Profile with new activity">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/>
</svg>
</button>
<span class="indicator__badge indicator__badge--dot indicator__badge--green" aria-hidden="true"></span>
</div>
</div>
</section>
</div>
</body>
</html>Indicator
Overlay badges and status dots positioned on top of any element.
Variants
- Online dot — green pulse dot on an avatar for presence status
- Count badge — numeric unread count overlaid on a button or icon
- Status badge — colored label for state (live, error, beta)
- Alert dot — small unread dot on an icon without a number
Positioning
The .indicator wrapper is position: relative. The .indicator__badge child uses position: absolute with configurable top/right offsets and translate(-50%, -50%) for precise corner anchoring.