Number Badge
Notification counters and presence dots — positioned on icons, buttons, or avatars with a clean JavaScript API

Number Badge

Number Badge extends Domma's badge system with positioned notification counters and presence dots. Use CSS-only classes for static indicators, or the JavaScript API to programmatically manage counters on any element — icons, buttons, avatars, and more.

Key Features

  • CSS-Only — standalone circular badges and dot indicators, no JS required
  • JS API — attach and manage counters on any element with E.numberBadge()
  • Web Component — declarative <domma-number-badge> with slot support
  • Auto-Hide — badge hides automatically when count reaches zero
  • Dot Mode — small presence indicator with no text
  • Pulse Animation — draw attention with a pulsing ring
  • 8 Colour Variants — matches all Domma semantic colours

At a Glance

5
CSS-only
JS API
Web Component
JD
Dot mode
!
Pulse
// CSS-only counter
<div class="badge-counter-wrapper">
    <button class="btn"><span data-icon="bell"></span></button>
    <span class="badge-counter">5</span>
</div>

// JavaScript API
const nb = E.numberBadge('#bell-btn', { count: 5, variant: 'danger' });
nb.increment();   // → 6
nb.setCount(0);   // badge hides automatically

// Web Component
<domma-number-badge count="5" variant="primary">
    <button class="btn"><span data-icon="bell"></span></button>
</domma-number-badge>

CSS-Only Usage

No JavaScript required. Apply CSS classes directly for static indicators.

Standalone Number Badges

Add .badge-number to any inline element. Single digits are circular; multi-digit numbers expand to a pill shape automatically via min-width.

3 7 12 42 99 8 1 100 5
<span class="badge-number">3</span>
<span class="badge-number badge-number-primary">7</span>
<span class="badge-number badge-number-success">42</span>
<span class="badge-number badge-number-danger">99</span>
<span class="badge-number badge-number-warning">8</span>
<span class="badge-number badge-number-info">1</span>

Dot Indicators

Add .badge-dot for a small presence indicator with no text content — ideal for online/offline status on avatars.

Default
Primary
Success
Danger
Warning
Info
<span class="badge-dot"></span>
<span class="badge-dot badge-dot-success"></span>
<span class="badge-dot badge-dot-danger"></span>

Positioned Counters

Wrap any element in .badge-counter-wrapper and add a sibling .badge-counter to position a counter at the top-right corner with a border ring.

5
Default
3
On a button
JD
Presence dot
12
Cart
!
Pulsing
<!-- Notification counter -->
<div class="badge-counter-wrapper">
    <button class="btn"><span data-icon="bell"></span></button>
    <span class="badge-counter">5</span>
</div>

<!-- Presence dot on avatar -->
<div class="badge-counter-wrapper">
    <div class="avatar">JD</div>
    <span class="badge-counter badge-dot badge-counter-success"></span>
</div>

<!-- Colour variant -->
<div class="badge-counter-wrapper">
    <button class="btn">Cart</button>
    <span class="badge-counter badge-counter-danger">12</span>
</div>

<!-- Pulsing counter -->
<div class="badge-counter-wrapper">
    <button class="btn"><span data-icon="bell"></span></button>
    <span class="badge-counter badge-counter-warning badge-pulse">!</span>
</div>

JavaScript API

Use E.numberBadge(selector, options) to attach a managed counter to any element. The badge tracks state, auto-shows/hides, and exposes a chainable API.

Initialisation

const nb = E.numberBadge('#bell-btn', {
    count: 5,           // Initial count (default: 0)
    variant: 'danger',  // Colour variant (default: 'danger')
    dot: false,         // Dot mode — no text
    pulse: false,       // Pulse animation
    borderColor: null   // Custom border ring colour
});

nb.increment();         // +1 → 6
nb.decrement();         // -1 → 5
nb.increment(5);        // +5 → 10
nb.setCount(0);         // Hides the badge automatically
nb.setCount(3);         // Shows the badge again
nb.setVariant('info');  // Change colour
nb.setDot(true);        // Switch to dot mode
nb.setPulse(true);      // Enable pulse
nb.getCount();          // → current count
nb.remove();            // Remove badge and restore element

Interactive Demo

Target element
Count: 0
Variant:

Multiple Independent Counters

Each E.numberBadge() call creates an independent instance.

Notifications
Messages
Cart
const bellBadge = E.numberBadge('#bell', { count: 3, variant: 'danger' });
const mailBadge = E.numberBadge('#mail', { count: 12, variant: 'primary' });
const cartBadge = E.numberBadge('#cart', { count: 0, variant: 'success' });

bellBadge.increment();
mailBadge.setCount(0);   // Hides automatically
cartBadge.setCount(5);

Web Component

The <domma-number-badge> custom element uses Shadow DOM and a <slot> to wrap any child content with a positioned counter. Declare it in HTML or create it with JS.

Declarative Usage

Default (danger)
Primary
Count = 0 (hidden)
AB
Dot mode
Pulsing
<!-- Default counter -->
<domma-number-badge count="5">
    <button class="btn"><span data-icon="bell"></span></button>
</domma-number-badge>

<!-- Primary variant -->
<domma-number-badge count="3" variant="primary">
    <button class="btn">Inbox</button>
</domma-number-badge>

<!-- Presence dot on avatar -->
<domma-number-badge dot variant="success">
    <div class="avatar">AB</div>
</domma-number-badge>

<!-- Pulsing counter -->
<domma-number-badge count="7" pulse variant="warning">
    <button class="btn"><span data-icon="bell"></span></button>
</domma-number-badge>

Programmatic API

Web component target
const badge = document.getElementById('my-badge');

badge.increment();
badge.decrement();
badge.setCount(10);
badge.setVariant('success');
badge.setDot(true);
badge.setPulse(true);

Real-World Patterns

App Navigation Bar

MyApp
4
12
JD

Inbox with Unread Counts

Inbox 24
Sent
Drafts 3
Spam 7
Archived
<div class="nav-item">
    Inbox <span class="badge-number badge-number-primary">24</span>
</div>
<div class="nav-item">
    Drafts <span class="badge-number badge-number-warning">3</span>
</div>

Online User List

AL
Online
BM
Away
CN
Offline
DR
Busy

Best Practices

Accessibility

  • aria-live built-in — The JS API adds aria-live="polite" and role="status" automatically so screen readers announce count changes.
  • Label the target — Add descriptive aria-label to icon buttons: aria-label="Notifications, 5 unread"
  • Dot mode — Pair dot-only badges with a visible label or tooltip; the dot alone conveys nothing to screen readers.

Design Guidelines

  • Trust auto-hide — The badge hides when count reaches 0; resist the urge to show "0"
  • Danger for alerts — Red counters signal unread/urgent items; use primary/info for neutral counts
  • Pulse sparingly — Reserve pulse for genuinely urgent alerts; overuse erodes its impact
  • Dot for presence — Use dot mode for online/away/offline indicators, not for counts

API Reference

Options

OptionTypeDefaultDescription
countnumber0Initial counter value
variantstring'danger'Colour variant: primary, secondary, success, danger, warning, info, light, dark
dotbooleanfalseShow as a dot (no text)
pulsebooleanfalseEnable pulse animation
borderColorstring|nullnullCustom border ring colour (overrides theme default)

Methods

MethodReturnsDescription
setCount(n)thisSet count to exact value; hides at 0 in non-dot mode
increment(by?)thisIncrement count by 1 (or by by)
decrement(by?)thisDecrement count by 1 (or by by); minimum 0
getCount()numberReturn current count
setVariant(v)thisChange colour variant
setDot(bool)thisToggle dot mode on/off
setPulse(bool)thisToggle pulse animation on/off
remove()voidRemove counter and restore element to original DOM position
destroy()voidAlias for remove()

CSS Classes

ClassDescription
.badge-numberStandalone circular/pill number badge
.badge-number-{variant}Colour variant (primary, success, danger, warning, info, secondary, light, dark)
.badge-dotSmall circular dot indicator (8px)
.badge-dot-{variant}Colour variant for dot
.badge-counter-wrapperRelative-positioned container for element + counter
.badge-counterAbsolute-positioned counter at top-right corner
.badge-counter-{variant}Colour variant for counter
.badge-pulseApply pulse animation to .badge-counter
.badge-counter-hiddenHides the counter (applied automatically when count = 0)

Config Engine

Number Badge is supported in the declarative config engine via $.setup().

$.setup({
    '#bell-btn': {
        component: 'numberBadge',
        options: {
            count: 0,
            variant: 'danger'
        }
    }
});

CSS Customisation

Number Badge uses standard Domma semantic colour tokens. Override globally or per-scope.

VariableControls
--dm-dangerDefault counter background colour
--dm-primaryPrimary variant colour
--dm-successSuccess variant colour
--dm-backgroundBorder ring colour (matches page background by default)
--dm-radius-fullBorder radius (9999px = circular/pill)
/* Match border ring to a dark card background */
.dark-card .badge-counter {
    border-color: var(--dm-surface-2);
}

/* Larger counter text */
.badge-counter {
    font-size: 0.75rem;
    min-width: 1.5rem;
    height: 1.5rem;
}

Full CSS Customisation Cheat-Sheet →

Related Elements