Skip to content

Badge

Experimental Alpha

This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.

The Badge component provides a versatile way to display counts, status indicators, and labels with multiple variants and sizes.

Examples

Vue
Lit
React
Live Preview
Default Badge

Variants

DefaultSuccessInfoWarningDangerNeutralMonochrome

Sizes

Extra SmallSmallMedium

Count Badges

199+23

Dot Badges

Status Indicators

Online
Away
Busy
Connecting

Positioning Badges

You can control the badge placement with CSS. To apply absolute positioning to the badge, be sure to apply position: relative on the button.

Inside Buttons (as content)

Inbox 99+

Absolute Position

Inbox 99+

Badges with Icon

3
3
3
99+
99+

Button Icon with Badge

Items in cart3
Items in cart3
Items in cart

CSS Parts Customization

Customize badge appearance using CSS Shadow Parts without breaking encapsulation.

Gradient BadgeMinimal Badge
View Vue Code
<template>
  <section>
    <!-- Default Badge -->
    <div class="mbe4">
      <VueBadge>Default Badge</VueBadge>
    </div>

    <!-- Variants -->
    <div class="mbe2">
      <h2>Variants</h2>
    </div>
    <div class="stacked-mobile mbe4">
      <VueBadge variant="default">Default</VueBadge>
      <VueBadge variant="success">Success</VueBadge>
      <VueBadge variant="info">Info</VueBadge>
      <VueBadge variant="warning">Warning</VueBadge>
      <VueBadge variant="danger">Danger</VueBadge>
      <VueBadge variant="neutral">Neutral</VueBadge>
      <VueBadge variant="monochrome">Monochrome</VueBadge>
    </div>

    <!-- Sizes -->
    <div class="mbe2">
      <h2>Sizes</h2>
    </div>
    <div class="stacked-mobile mbe4">
      <VueBadge size="xs">Extra Small</VueBadge>
      <VueBadge size="sm">Small</VueBadge>
      <VueBadge size="md">Medium</VueBadge>
    </div>

    <!-- Count Badges -->
    <div class="mbe2">
      <h2>Count Badges</h2>
    </div>
    <div class="stacked-mobile mbe4">
      <VueBadge variant="success">1</VueBadge>
      <VueBadge variant="danger">99+</VueBadge>
      <VueBadge variant="info">23</VueBadge>
    </div>

    <!-- Dot Badges -->
    <div class="mbe2">
      <h2>Dot Badges</h2>
    </div>
    <div class="stacked-mobile mbe4">
      <VueBadge
        dot
        variant="default"
      ></VueBadge>
      <VueBadge
        dot
        variant="info"
      ></VueBadge>
      <VueBadge
        dot
        variant="success"
      ></VueBadge>
      <VueBadge
        dot
        variant="warning"
      ></VueBadge>
      <VueBadge
        dot
        variant="danger"
      ></VueBadge>
      <VueBadge
        dot
        variant="monochrome"
      ></VueBadge>
    </div>

    <!-- Status Indicators -->
    <div class="mbe2">
      <h2>Status Indicators</h2>
    </div>
    <div
      style="display: flex; flex-direction: column; gap: 1rem;"
      class="mbe4"
    >
      <div style="display: flex; align-items: center; gap: 0.5rem;">
        <VueBadge
          dot
          variant="success"
        />
        Online
      </div>
      <div style="display: flex; align-items: center; gap: 0.5rem;">
        <VueBadge
          dot
          variant="warning"
        />
        Away
      </div>
      <div style="display: flex; align-items: center; gap: 0.5rem;">
        <VueBadge
          dot
          variant="danger"
        />
        Busy
      </div>
      <div style="display: flex; align-items: center; gap: 0.5rem;">
        <VueBadge
          dot
          variant="info"
        />
        Connecting
      </div>
    </div>

    <div class="mbe4">
      <h2>Positioning Badges</h2>
    </div>
    <VueAlert
      class="mbe2"
      borderedLeft
      type="info"
    >
      <div class="flex-inline items-center justify-center">
        You can control the badge placement with CSS. To apply absolute positioning to the badge, be sure to apply position: relative on the button.
      </div>
    </VueAlert>
    <div class="mbe4">
      <h3>Inside Buttons (as content)</h3>
    </div>
    <div class="mbe4">
      <VueButton
        bordered
        variant="primary"
        shape="capsule"
      >
        Inbox
        <VueBadge
          variant="danger"
          size="sm"
          style="margin-left: var(--ag-space-1);"
        >99+</VueBadge>
      </VueButton>
    </div>
    <div class="mbs4 mbe4">
      <h3>Absolute Position</h3>
    </div>
    <div class="mbe4">
      <VueButton
        bordered
        variant="primary"
        shape="capsule"
        style="position: relative;"
      >
        Inbox
        <VueBadge
          variant="danger"
          size="sm"
          style="position: absolute; top: -10px; right: -13px;"
        >99+</VueBadge>
      </VueButton>
    </div>
    <!-- Badge on Icon -->
    <div class="mbe4">
      <h2>Badges with Icon</h2>
    </div>
    <div class="stacked-mobile mbe4">
      <div style="position: relative; display: inline-block; align-self: flex-start;">
        <VueIcon
          noFill
          size="16"
        >
          <Bell />
        </VueIcon>
        <VueBadge
          variant="danger"
          size="xs"
          style="position: absolute; top: -6px; right: -7px;"
        >
          3
        </VueBadge>
      </div>
      <div style="position: relative; display: inline-block; align-self: flex-start;">
        <VueIcon
          noFill
          size="20"
        >
          <Bell />
        </VueIcon>
        <VueBadge
          variant="danger"
          size="sm"
          style="position: absolute; top: -7px; right: -9px;"
        >
          3
        </VueBadge>
      </div>
      <div style="position: relative; display: inline-block; align-self: flex-start;">
        <VueIcon
          noFill
          size="24"
        >
          <Bell />
        </VueIcon>
        <VueBadge
          variant="danger"
          size="md"
          style="position: absolute; top: -7px; right: -10px;"
        >
          3
        </VueBadge>
      </div>
      <div
        class="mis2"
        style="position: relative; display: inline-block; align-self: flex-start;"
      >
        <VueIcon
          noFill
          size="16"
        >
          <Bell />
        </VueIcon>
        <VueBadge
          variant="danger"
          size="sm"
          dot
          style="position: absolute; top: 0px; right: -1px;"
        >
        </VueBadge>
      </div>
      <div style="position: relative; display: inline-block; align-self: flex-start;">
        <VueIcon
          noFill
          size="24"
        >
          <Bell />
        </VueIcon>
        <VueBadge
          variant="danger"
          size="md"
          dot
          style="position: absolute; top: -1px; right: -1px;"
        >
        </VueBadge>
      </div>
      <div style="position: relative; display: inline-block; align-self: flex-start;">
        <VueIcon
          noFill
          size="24"
        >
          <Mail />
        </VueIcon>
        <VueBadge
          variant="success"
          size="md"
          dot
          style="position: absolute; top: -3px; right: -4px;"
        >
        </VueBadge>
      </div>
      <div
        class="mis2"
        style="position: relative; display: inline-block; align-self: flex-start;"
      >
        <VueIcon
          noFill
          size="24"
        >
          <Mail />
        </VueIcon>
        <VueBadge
          variant="warning"
          size="md"
          dot
          style="position: absolute; top: -3px; right: -4px;"
        >
        </VueBadge>
      </div>
      <div
        class="mis2"
        style="position: relative; display: inline-block; align-self: flex-start;"
      >
        <VueIcon
          noFill
          size="24"
        >
          <Mail />
        </VueIcon>
        <VueBadge
          variant="danger"
          size="xs"
          style="position: absolute; top: -3px; right: -16px;"
        >99+</VueBadge>
      </div>
      <div
        class="mis3"
        style="position: relative; display: inline-block; align-self: flex-start;"
      >
        <VueIcon
          noFill
          size="24"
        >
          <Mail />
        </VueIcon>
        <VueBadge
          variant="danger"
          size="sm"
          style="position: absolute; top: -9px; right: -30px;"
        >99+</VueBadge>
      </div>
    </div>
    <div class="mbe4">
      <h2>Button Icon with Badge</h2>
    </div>
    <div style="position: relative; display: inline-block;">
      <VueButton
        bordered
        variant="info"
        shape="rounded-square"
        style="position: relative;"
      >
        <VueIcon
          noFill
          size="24"
        >
          <ShoppingCart />
        </VueIcon>
        <VueVisuallyHidden>Items in cart</VueVisuallyHidden>
        <VueBadge
          variant="danger"
          size="sm"
          style="position: absolute; top: -9px; right: -13px;"
        >3</VueBadge>
      </VueButton>
    </div>
    <div
      class="mis8"
      style="position: relative; display: inline-block;"
    >
      <VueButton
        bordered
        variant="info"
        shape="rounded-square"
        style="position: relative;"
      >
        <VueIcon
          noFill
          size="24"
        >
          <ShoppingCart />
        </VueIcon>
        <VueVisuallyHidden>Items in cart</VueVisuallyHidden>
        <VueBadge
          variant="default"
          size="sm"
          style="position: absolute; top: -9px; right: -13px;"
        >3</VueBadge>
      </VueButton>
    </div>
    <div
      class="mis8"
      style="position: relative; display: inline-block;"
    >
      <VueButton
        bordered
        variant="info"
        shape="rounded-square"
        style="position: relative;"
      >
        <VueIcon
          noFill
          size="24"
        >
          <ShoppingCart />
        </VueIcon>
        <VueVisuallyHidden>Items in cart</VueVisuallyHidden>
        <VueBadge
          variant="success"
          size="md"
          dot
          style="position: absolute; top: -6px; right: -7px;"
        ></VueBadge>
      </VueButton>
    </div>
    <!-- CSS Parts Customization -->
    <div class="mbe4">
      <h2>CSS Parts Customization</h2>
      <p
        class="mbe2"
        style="color: var(--ag-text-secondary); font-size: 0.875rem;"
      >
        Customize badge appearance using CSS Shadow Parts without breaking encapsulation.
      </p>
    </div>
    <div class="stacked-mobile mbe4">
      <VueBadge class="custom-gradient-badge">Gradient Badge</VueBadge>
      <VueBadge class="custom-minimal-badge">Minimal Badge</VueBadge>
    </div>
  </section>
</template>

<script>
import { VueBadge } from "agnosticui-core/badge/vue";
import VueButton from "agnosticui-core/button/vue";
import { VueIcon } from "agnosticui-core/icon/vue";
import { Mail, Bell, Info, ShoppingCart } from "lucide-vue-next";
import VueAlert from "agnosticui-core/alert/vue";
import { VueVisuallyHidden } from "agnosticui-core/visually-hidden/vue";

export default {
  name: "BadgeExamples",
  components: {
    VueBadge,
    VueVisuallyHidden,
    VueButton,
    VueIcon,
    Bell,
    Info,
    Mail,
    ShoppingCart,
    VueAlert,
  },
};
</script>

<style scoped>
/* CSS Parts customization examples */

/* Gradient badge style */
.custom-gradient-badge::part(ag-badge) {
  background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
  color: white;
  font-weight: 600;
  padding: 0.5rem 1rem;
}

/* Minimal badge */
.custom-minimal-badge::part(ag-badge) {
  background: var(--ag-background-subtle);
  color: var(--ag-text-secondary);
  border-radius: 6px;
  font-size: 0.85rem;
  padding: 0.25rem 0.75rem;
}
</style>
Live Preview
View Lit / Web Component Code
import { LitElement, html, svg } from 'lit';
import 'agnosticui-core/badge';
import 'agnosticui-core/button';
import 'agnosticui-core/icon';
import 'agnosticui-core/visually-hidden';
import 'agnosticui-core/alert';

export class BadgeLitExamples extends LitElement {
  // Render in light DOM to access global utility classes
  createRenderRoot() {
    return this;
  }

  // Helper method for Bell icon SVG
  bellIcon(size = 24) {
    return svg`
      <svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" />
        <path d="M10.3 21a1.94 1.94 0 0 0 3.4 0" />
      </svg>
    `;
  }

  // Helper method for Mail icon SVG
  mailIcon(size = 24) {
    return svg`
      <svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <rect width="20" height="16" x="2" y="4" rx="2" />
        <path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
      </svg>
    `;
  }

  // Helper method for ShoppingCart icon SVG
  shoppingCartIcon(size = 24) {
    return svg`
      <svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <circle cx="8" cy="21" r="1" />
        <circle cx="19" cy="21" r="1" />
        <path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12" />
      </svg>
    `;
  }

  render() {
    return html`
      <section>
        <!-- Default Badge -->
        <div class="mbe4">
          <ag-badge>Default Badge</ag-badge>
        </div>

        <!-- Variants -->
        <div class="mbe2">
          <h2>Variants</h2>
        </div>
        <div class="stacked-mobile mbe4">
          <ag-badge variant="default">Default</ag-badge>
          <ag-badge variant="success">Success</ag-badge>
          <ag-badge variant="info">Info</ag-badge>
          <ag-badge variant="warning">Warning</ag-badge>
          <ag-badge variant="danger">Danger</ag-badge>
          <ag-badge variant="neutral">Neutral</ag-badge>
          <ag-badge variant="monochrome">Monochrome</ag-badge>
        </div>

        <!-- Sizes -->
        <div class="mbe2">
          <h2>Sizes</h2>
        </div>
        <div class="stacked-mobile mbe4">
          <ag-badge size="xs">Extra Small</ag-badge>
          <ag-badge size="sm">Small</ag-badge>
          <ag-badge size="md">Medium</ag-badge>
        </div>

        <!-- Count Badges -->
        <div class="mbe2">
          <h2>Count Badges</h2>
        </div>
        <div class="stacked-mobile mbe4">
          <ag-badge variant="success">1</ag-badge>
          <ag-badge variant="danger">99+</ag-badge>
          <ag-badge variant="info">23</ag-badge>
        </div>

        <!-- Dot Badges -->
        <div class="mbe2">
          <h2>Dot Badges</h2>
        </div>
        <div class="stacked-mobile mbe4">
          <ag-badge dot variant="default"></ag-badge>
          <ag-badge dot variant="info"></ag-badge>
          <ag-badge dot variant="success"></ag-badge>
          <ag-badge dot variant="warning"></ag-badge>
          <ag-badge dot variant="danger"></ag-badge>
          <ag-badge dot variant="monochrome"></ag-badge>
        </div>

        <!-- Status Indicators -->
        <div class="mbe2">
          <h2>Status Indicators</h2>
        </div>
        <div
          style="display: flex; flex-direction: column; gap: 1rem;"
          class="mbe4"
        >
          <div style="display: flex; align-items: center; gap: 0.5rem;">
            <ag-badge dot variant="success"></ag-badge>
            Online
          </div>
          <div style="display: flex; align-items: center; gap: 0.5rem;">
            <ag-badge dot variant="warning"></ag-badge>
            Away
          </div>
          <div style="display: flex; align-items: center; gap: 0.5rem;">
            <ag-badge dot variant="danger"></ag-badge>
            Busy
          </div>
          <div style="display: flex; align-items: center; gap: 0.5rem;">
            <ag-badge dot variant="info"></ag-badge>
            Connecting
          </div>
        </div>

        <div class="mbe4">
          <h2>Positioning Badges</h2>
        </div>
        <ag-alert
          class="mbe2"
          bordered-left
          type="info"
        >
          <div class="flex-inline items-center justify-center">
            You can control the badge placement with CSS. To apply absolute positioning to the badge, be sure to apply position: relative on the button.
          </div>
        </ag-alert>
        <div class="mbe4">
          <h3>Inside Buttons (as content)</h3>
        </div>
        <div class="mbe4">
          <ag-button
            bordered
            variant="primary"
            shape="capsule"
          >
            Inbox
            <ag-badge
              variant="danger"
              size="sm"
              style="margin-left: var(--ag-space-1);"
            >99+</ag-badge>
          </ag-button>
        </div>
        <div class="mbs4 mbe4">
          <h3>Absolute Position</h3>
        </div>
        <div class="mbe4">
          <ag-button
            bordered
            variant="primary"
            shape="capsule"
            style="position: relative;"
          >
            Inbox
            <ag-badge
              variant="danger"
              size="sm"
              style="position: absolute; top: -10px; right: -13px;"
            >99+</ag-badge>
          </ag-button>
        </div>
        <!-- Badge on Icon -->
        <div class="mbe4">
          <h2>Badges with Icon</h2>
        </div>
        <div class="stacked-mobile mbe4">
          <div style="position: relative; display: inline-block; align-self: flex-start;">
            <ag-icon no-fill size="16">
              ${this.bellIcon(16)}
            </ag-icon>
            <ag-badge
              variant="danger"
              size="xs"
              style="position: absolute; top: -6px; right: -7px;"
            >
              3
            </ag-badge>
          </div>
          <div style="position: relative; display: inline-block; align-self: flex-start;">
            <ag-icon no-fill size="20">
              ${this.bellIcon(20)}
            </ag-icon>
            <ag-badge
              variant="danger"
              size="sm"
              style="position: absolute; top: -7px; right: -9px;"
            >
              3
            </ag-badge>
          </div>
          <div style="position: relative; display: inline-block; align-self: flex-start;">
            <ag-icon no-fill size="24">
              ${this.bellIcon(24)}
            </ag-icon>
            <ag-badge
              variant="danger"
              size="md"
              style="position: absolute; top: -7px; right: -10px;"
            >
              3
            </ag-badge>
          </div>
          <div
            class="mis2"
            style="position: relative; display: inline-block; align-self: flex-start;"
          >
            <ag-icon no-fill size="16">
              ${this.bellIcon(16)}
            </ag-icon>
            <ag-badge
              variant="danger"
              size="sm"
              dot
              style="position: absolute; top: 0px; right: -1px;"
            >
            </ag-badge>
          </div>
          <div style="position: relative; display: inline-block; align-self: flex-start;">
            <ag-icon no-fill size="24">
              ${this.bellIcon(24)}
            </ag-icon>
            <ag-badge
              variant="danger"
              size="md"
              dot
              style="position: absolute; top: -1px; right: -1px;"
            >
            </ag-badge>
          </div>
          <div style="position: relative; display: inline-block; align-self: flex-start;">
            <ag-icon no-fill size="24">
              ${this.mailIcon(24)}
            </ag-icon>
            <ag-badge
              variant="success"
              size="md"
              dot
              style="position: absolute; top: -3px; right: -4px;"
            >
            </ag-badge>
          </div>
          <div
            class="mis2"
            style="position: relative; display: inline-block; align-self: flex-start;"
          >
            <ag-icon no-fill size="24">
              ${this.mailIcon(24)}
            </ag-icon>
            <ag-badge
              variant="warning"
              size="md"
              dot
              style="position: absolute; top: -3px; right: -4px;"
            >
            </ag-badge>
          </div>
          <div
            class="mis2"
            style="position: relative; display: inline-block; align-self: flex-start;"
          >
            <ag-icon no-fill size="24">
              ${this.mailIcon(24)}
            </ag-icon>
            <ag-badge
              variant="danger"
              size="xs"
              style="position: absolute; top: -3px; right: -16px;"
            >99+</ag-badge>
          </div>
          <div
            class="mis3"
            style="position: relative; display: inline-block; align-self: flex-start;"
          >
            <ag-icon no-fill size="24">
              ${this.mailIcon(24)}
            </ag-icon>
            <ag-badge
              variant="danger"
              size="sm"
              style="position: absolute; top: -9px; right: -30px;"
            >99+</ag-badge>
          </div>
        </div>
        <div class="mbe4">
          <h2>Button Icon with Badge</h2>
        </div>
        <div style="position: relative; display: inline-block;">
          <ag-button
            bordered
            variant="info"
            shape="rounded-square"
            style="position: relative;"
          >
            <ag-icon no-fill size="24">
              ${this.shoppingCartIcon(24)}
            </ag-icon>
            <ag-visually-hidden>Items in cart</ag-visually-hidden>
            <ag-badge
              variant="danger"
              size="sm"
              style="position: absolute; top: -9px; right: -13px;"
            >3</ag-badge>
          </ag-button>
        </div>
        <div
          class="mis8"
          style="position: relative; display: inline-block;"
        >
          <ag-button
            bordered
            variant="info"
            shape="rounded-square"
            style="position: relative;"
          >
            <ag-icon no-fill size="24">
              ${this.shoppingCartIcon(24)}
            </ag-icon>
            <ag-visually-hidden>Items in cart</ag-visually-hidden>
            <ag-badge
              variant="default"
              size="sm"
              style="position: absolute; top: -9px; right: -13px;"
            >3</ag-badge>
          </ag-button>
        </div>
        <div
          class="mis8"
          style="position: relative; display: inline-block;"
        >
          <ag-button
            bordered
            variant="info"
            shape="rounded-square"
            style="position: relative;"
          >
            <ag-icon no-fill size="24">
              ${this.shoppingCartIcon(24)}
            </ag-icon>
            <ag-visually-hidden>Items in cart</ag-visually-hidden>
            <ag-badge
              variant="success"
              size="md"
              dot
              style="position: absolute; top: -6px; right: -7px;"
            ></ag-badge>
          </ag-button>
        </div>
        <!-- CSS Parts Customization -->
        <div class="mbe4">
          <h2>CSS Parts Customization</h2>
          <p
            class="mbe2"
            style="color: var(--ag-text-secondary); font-size: 0.875rem;"
          >
            Customize badge appearance using CSS Shadow Parts without breaking encapsulation.
          </p>
        </div>
        <div class="stacked-mobile mbe4">
          <ag-badge class="custom-gradient-badge">Gradient Badge</ag-badge>
          <ag-badge class="custom-minimal-badge">Minimal Badge</ag-badge>
        </div>

        <style>
          /* CSS Parts customization examples */

          /* Gradient badge style */
          .custom-gradient-badge::part(ag-badge) {
            background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
            color: white;
            font-weight: 600;
            padding: 0.5rem 1rem;
          }

          /* Minimal badge */
          .custom-minimal-badge::part(ag-badge) {
            background: var(--ag-background-subtle);
            color: var(--ag-text-secondary);
            border-radius: 6px;
            font-size: 0.85rem;
            padding: 0.25rem 0.75rem;
          }
        </style>
      </section>
    `;
  }
}

customElements.define('badge-lit-examples', BadgeLitExamples);

Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.

View React Code
import { ReactBadge } from "agnosticui-core/badge/react";
import { ReactButton } from "agnosticui-core/button/react";
import { ReactIcon } from "agnosticui-core/icon/react";
import { ReactVisuallyHidden } from "agnosticui-core/visually-hidden/react";
import { ReactAlert } from "agnosticui-core/alert/react";
import { Mail, Bell, ShoppingCart } from "lucide-react";

export default function BadgeReactExamples() {
  return (
    <section>
      {/* Default Badge */}
      <div className="mbe4">
        <ReactBadge>Default Badge</ReactBadge>
      </div>

      {/* Variants */}
      <div className="mbe2">
        <h2>Variants</h2>
      </div>
      <div className="stacked-mobile mbe4">
        <ReactBadge variant="default">Default</ReactBadge>
        <ReactBadge variant="success">Success</ReactBadge>
        <ReactBadge variant="info">Info</ReactBadge>
        <ReactBadge variant="warning">Warning</ReactBadge>
        <ReactBadge variant="danger">Danger</ReactBadge>
        <ReactBadge variant="neutral">Neutral</ReactBadge>
        <ReactBadge variant="monochrome">Monochrome</ReactBadge>
      </div>

      {/* Sizes */}
      <div className="mbe2">
        <h2>Sizes</h2>
      </div>
      <div className="stacked-mobile mbe4">
        <ReactBadge size="xs">Extra Small</ReactBadge>
        <ReactBadge size="sm">Small</ReactBadge>
        <ReactBadge size="md">Medium</ReactBadge>
      </div>

      {/* Count Badges */}
      <div className="mbe2">
        <h2>Count Badges</h2>
      </div>
      <div className="stacked-mobile mbe4">
        <ReactBadge variant="success">1</ReactBadge>
        <ReactBadge variant="danger">99+</ReactBadge>
        <ReactBadge variant="info">23</ReactBadge>
      </div>

      {/* Dot Badges */}
      <div className="mbe2">
        <h2>Dot Badges</h2>
      </div>
      <div className="stacked-mobile mbe4">
        <ReactBadge dot variant="default"></ReactBadge>
        <ReactBadge dot variant="info"></ReactBadge>
        <ReactBadge dot variant="success"></ReactBadge>
        <ReactBadge dot variant="warning"></ReactBadge>
        <ReactBadge dot variant="danger"></ReactBadge>
        <ReactBadge dot variant="monochrome"></ReactBadge>
      </div>

      {/* Status Indicators */}
      <div className="mbe2">
        <h2>Status Indicators</h2>
      </div>
      <div
        style={{ display: "flex", flexDirection: "column", gap: "1rem" }}
        className="mbe4"
      >
        <div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
          <ReactBadge dot variant="success" />
          Online
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
          <ReactBadge dot variant="warning" />
          Away
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
          <ReactBadge dot variant="danger" />
          Busy
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
          <ReactBadge dot variant="info" />
          Connecting
        </div>
      </div>

      <div className="mbe4">
        <h2>Positioning Badges</h2>
      </div>
      <ReactAlert
        className="mbe2"
        borderedLeft
        type="info"
      >
        <div className="flex-inline items-center justify-center">
          You can control the badge placement with CSS. To apply absolute positioning to the badge, be sure to apply position: relative on the button.
        </div>
      </ReactAlert>
      <div className="mbe4">
        <h3>Inside Buttons (as content)</h3>
      </div>
      <div className="mbe4">
        <ReactButton
          bordered
          variant="primary"
          shape="capsule"
        >
          Inbox
          <ReactBadge
            variant="danger"
            size="sm"
            style={{ marginLeft: "var(--ag-space-1)" }}
          >99+</ReactBadge>
        </ReactButton>
      </div>
      <div className="mbs4 mbe4">
        <h3>Absolute Position</h3>
      </div>
      <div className="mbe4">
        <ReactButton
          bordered
          variant="primary"
          shape="capsule"
          style={{ position: "relative" }}
        >
          Inbox
          <ReactBadge
            variant="danger"
            size="sm"
            style={{ position: "absolute", top: "-10px", right: "-13px" }}
          >99+</ReactBadge>
        </ReactButton>
      </div>
      {/* Badge on Icon */}
      <div className="mbe4">
        <h2>Badges with Icon</h2>
      </div>
      <div className="stacked-mobile mbe4">
        <div style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}>
          <ReactIcon noFill size="16">
            <Bell size={16} />
          </ReactIcon>
          <ReactBadge
            variant="danger"
            size="xs"
            style={{ position: "absolute", top: "-6px", right: "-7px" }}
          >
            3
          </ReactBadge>
        </div>
        <div style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}>
          <ReactIcon noFill size="20">
            <Bell size={20} />
          </ReactIcon>
          <ReactBadge
            variant="danger"
            size="sm"
            style={{ position: "absolute", top: "-7px", right: "-9px" }}
          >
            3
          </ReactBadge>
        </div>
        <div style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}>
          <ReactIcon noFill size="24">
            <Bell size={24} />
          </ReactIcon>
          <ReactBadge
            variant="danger"
            size="md"
            style={{ position: "absolute", top: "-7px", right: "-10px" }}
          >
            3
          </ReactBadge>
        </div>
        <div
          className="mis2"
          style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}
        >
          <ReactIcon noFill size="16">
            <Bell size={16} />
          </ReactIcon>
          <ReactBadge
            variant="danger"
            size="sm"
            dot
            style={{ position: "absolute", top: "0px", right: "-1px" }}
          >
          </ReactBadge>
        </div>
        <div style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}>
          <ReactIcon noFill size="24">
            <Bell size={24} />
          </ReactIcon>
          <ReactBadge
            variant="danger"
            size="md"
            dot
            style={{ position: "absolute", top: "-1px", right: "-1px" }}
          >
          </ReactBadge>
        </div>
        <div style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}>
          <ReactIcon noFill size="24">
            <Mail size={24} />
          </ReactIcon>
          <ReactBadge
            variant="success"
            size="md"
            dot
            style={{ position: "absolute", top: "-3px", right: "-4px" }}
          >
          </ReactBadge>
        </div>
        <div
          className="mis2"
          style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}
        >
          <ReactIcon noFill size="24">
            <Mail size={24} />
          </ReactIcon>
          <ReactBadge
            variant="warning"
            size="md"
            dot
            style={{ position: "absolute", top: "-3px", right: "-4px" }}
          >
          </ReactBadge>
        </div>
        <div
          className="mis2"
          style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}
        >
          <ReactIcon noFill size="24">
            <Mail size={24} />
          </ReactIcon>
          <ReactBadge
            variant="danger"
            size="xs"
            style={{ position: "absolute", top: "-3px", right: "-16px" }}
          >99+</ReactBadge>
        </div>
        <div
          className="mis3"
          style={{ position: "relative", display: "inline-block", alignSelf: "flex-start" }}
        >
          <ReactIcon noFill size="24">
            <Mail size={24} />
          </ReactIcon>
          <ReactBadge
            variant="danger"
            size="sm"
            style={{ position: "absolute", top: "-9px", right: "-30px" }}
          >99+</ReactBadge>
        </div>
      </div>
      <div className="mbe4">
        <h2>Button Icon with Badge</h2>
      </div>
      <div style={{ position: "relative", display: "inline-block" }}>
        <ReactButton
          bordered
          variant="info"
          shape="rounded-square"
          style={{ position: "relative" }}
        >
          <ReactIcon noFill size="24">
            <ShoppingCart size={24} />
          </ReactIcon>
          <ReactVisuallyHidden>Items in cart</ReactVisuallyHidden>
          <ReactBadge
            variant="danger"
            size="sm"
            style={{ position: "absolute", top: "-9px", right: "-13px" }}
          >3</ReactBadge>
        </ReactButton>
      </div>
      <div
        className="mis8"
        style={{ position: "relative", display: "inline-block" }}
      >
        <ReactButton
          bordered
          variant="info"
          shape="rounded-square"
          style={{ position: "relative" }}
        >
          <ReactIcon noFill size="24">
            <ShoppingCart size={24} />
          </ReactIcon>
          <ReactVisuallyHidden>Items in cart</ReactVisuallyHidden>
          <ReactBadge
            variant="default"
            size="sm"
            style={{ position: "absolute", top: "-9px", right: "-13px" }}
          >3</ReactBadge>
        </ReactButton>
      </div>
      <div
        className="mis8"
        style={{ position: "relative", display: "inline-block" }}
      >
        <ReactButton
          bordered
          variant="info"
          shape="rounded-square"
          style={{ position: "relative" }}
        >
          <ReactIcon noFill size="24">
            <ShoppingCart size={24} />
          </ReactIcon>
          <ReactVisuallyHidden>Items in cart</ReactVisuallyHidden>
          <ReactBadge
            variant="success"
            size="md"
            dot
            style={{ position: "absolute", top: "-6px", right: "-7px" }}
          ></ReactBadge>
        </ReactButton>
      </div>
      {/* CSS Parts Customization */}
      <div className="mbe4">
        <h2>CSS Parts Customization</h2>
        <p
          className="mbe2"
          style={{ color: "var(--ag-text-secondary)", fontSize: "0.875rem" }}
        >
          Customize badge appearance using CSS Shadow Parts without breaking encapsulation.
        </p>
      </div>
      <div className="stacked-mobile mbe4">
        <ReactBadge className="custom-gradient-badge">Gradient Badge</ReactBadge>
        <ReactBadge className="custom-minimal-badge">Minimal Badge</ReactBadge>
      </div>

      {/* CSS Shadow Parts customization styles */}
      <style>{`
        /* CSS Parts customization examples */

        /* Gradient badge style */
        .custom-gradient-badge::part(ag-badge) {
          background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
          color: white;
          font-weight: 600;
          padding: 0.5rem 1rem;
        }

        /* Minimal badge */
        .custom-minimal-badge::part(ag-badge) {
          background: var(--ag-background-subtle);
          color: var(--ag-text-secondary);
          border-radius: 6px;
          font-size: 0.85rem;
          padding: 0.25rem 0.75rem;
        }
      `}</style>
    </section>
  );
}
Open in StackBlitz

Usage

TIP

The framework examples below import AgnosticUI as an npm package. Alternatively, you can use the CLI for complete control, AI/LLM visibility, and full code ownership:

bash
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add Badge

The CLI copies source code directly into your project, giving you full visibility and control. After running npx ag add, you'll receive exact import instructions.

Vue
vue
<template>
  <section>
    <VueBadge>New</VueBadge>

    <VueBadge variant="default">Default</VueBadge>
    <VueBadge variant="success">Success</VueBadge>
    <VueBadge variant="info">Info</VueBadge>
    <VueBadge variant="warning">Warning</VueBadge>
    <VueBadge variant="danger">Danger</VueBadge>
    <VueBadge variant="neutral">Neutral</VueBadge>
    <VueBadge variant="monochrome">Monochrome</VueBadge>

    <VueBadge size="xs">XS</VueBadge>
    <VueBadge size="sm">Small</VueBadge>
    <VueBadge size="md">Medium</VueBadge>

    <VueBadge variant="danger">99+</VueBadge>
    <VueBadge variant="success">5</VueBadge>

    <VueBadge dot variant="success" />
    <VueBadge dot variant="warning" />
    <VueBadge dot variant="danger" />

    <div style="display: flex; align-items: center; gap: 0.5rem;">
      <VueBadge dot variant="success" />
      Online
    </div>

    <VueButton variant="primary">
      Notifications
      <VueBadge variant="danger" size="sm">99+</VueBadge>
    </VueButton>

    <div style="position: relative; display: inline-block;">
      <VueIcon size="24">
      </VueIcon>
      <VueBadge
        variant="danger"
        size="xs"
        style="position: absolute; top: -6px; right: -7px;"
      >
        3
      </VueBadge>
    </div>
  </section>
</template>

<script>
import { VueBadge } from "agnosticui-core/badge/vue";
import VueButton from "agnosticui-core/button/vue";
import { VueIcon } from "agnosticui-core/icon/vue";

export default {
  name: "BadgeExample",
  components: { VueBadge, VueButton, VueIcon },
};
</script>
React
tsx
import { ReactBadge } from "agnosticui-core/badge/react";
import { ReactButton } from "agnosticui-core/button/react";
import { ReactIcon } from "agnosticui-core/icon/react";

export default function BadgeExample() {
  return (
    <section>
      <ReactBadge>New</ReactBadge>

      <ReactBadge variant="default">Default</ReactBadge>
      <ReactBadge variant="success">Success</ReactBadge>
      <ReactBadge variant="info">Info</ReactBadge>
      <ReactBadge variant="warning">Warning</ReactBadge>
      <ReactBadge variant="danger">Danger</ReactBadge>
      <ReactBadge variant="neutral">Neutral</ReactBadge>

      <ReactBadge size="xs">XS</ReactBadge>
      <ReactBadge size="sm">Small</ReactBadge>
      <ReactBadge size="md">Medium</ReactBadge>

      <ReactBadge variant="danger">99+</ReactBadge>
      <ReactBadge variant="success">5</ReactBadge>

      <ReactBadge dot variant="success" />
      <ReactBadge dot variant="warning" />
      <ReactBadge dot variant="danger" />

      <div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
        <ReactBadge dot variant="success" />
        Online
      </div>

      <ReactButton variant="primary">
        Notifications
        <ReactBadge variant="danger" size="sm">99+</ReactBadge>
      </ReactButton>

      <div style={{ position: "relative", display: "inline-block" }}>
        <ReactIcon size="24">
        </ReactIcon>
        <ReactBadge
          variant="danger"
          size="xs"
          style={{ position: "absolute", top: "-6px", right: "-7px" }}
        >
          3
        </ReactBadge>
      </div>
    </section>
  );
}
Lit (Web Components)
html
<script type="module">
  import "agnosticui-core/badge";
  import "agnosticui-core/button";
  import "agnosticui-core/icon";
</script>

<section>
  <ag-badge>New</ag-badge>

  <ag-badge variant="default">Default</ag-badge>
  <ag-badge variant="success">Success</ag-badge>
  <ag-badge variant="info">Info</ag-badge>
  <ag-badge variant="warning">Warning</ag-badge>
  <ag-badge variant="danger">Danger</ag-badge>
  <ag-badge variant="neutral">Neutral</ag-badge>

  <ag-badge size="xs">XS</ag-badge>
  <ag-badge size="sm">Small</ag-badge>
  <ag-badge size="md">Medium</ag-badge>

  <ag-badge variant="danger">99+</ag-badge>
  <ag-badge variant="success">5</ag-badge>

  <ag-badge dot variant="success"></ag-badge>
  <ag-badge dot variant="warning"></ag-badge>
  <ag-badge dot variant="danger"></ag-badge>

  <div style="display: flex; align-items: center; gap: 0.5rem;">
    <ag-badge dot variant="success"></ag-badge>
    Online
  </div>

  <ag-button variant="primary">
    Notifications
    <ag-badge variant="danger" size="sm">99+</ag-badge>
  </ag-button>

  <div style="position: relative; display: inline-block;">
    <ag-icon size="24">
    </ag-icon>
    <ag-badge
      variant="danger"
      size="xs"
      style="position: absolute; top: -6px; right: -7px;"
    >
      3
    </ag-badge>
  </div>
</section>

Props

PropTypeDefaultDescription
variant'default' | 'success' | 'info' | 'warning' | 'danger' | 'neutral''default'Visual color variant
size'xs' | 'sm' | 'md''md'Size of the badge
dotbooleanfalseRender as a small circular dot (for status indicators)
valuenumber | nullnullNumeric value to display
maxnumber99Maximum value before showing "+" suffix (e.g., "99+")
interactivebooleanfalseMake badge clickable/interactive
statusLabelstring | nullnullARIA label for status badges (especially important for dot badges)
live'off' | 'polite' | 'assertive''off'ARIA live region politeness setting for dynamic count updates
hiddenFromATbooleanfalseHide from assistive technologies

Events

EventDetailDescription
badge:click (Vue: @badge:click, React: onBadgeClick)CustomEventEmitted when an interactive badge is clicked

Note: The click event is only emitted when interactive prop is true.

Accessibility

The Badge component follows accessibility best practices:

  • Automatic aria-hidden="true" for decorative dot badges without status labels
  • aria-label support via statusLabel prop for meaningful descriptions
  • aria-live regions for dynamic count updates (configure with live prop)
  • Role button for interactive badges with proper keyboard support
  • Single-character badges automatically get circular shape for better visual balance

Status Badges

For status indicator badges (dots), always provide a statusLabel:

Vue
vue
<div style="display: flex; align-items: center; gap: 0.5rem;">
  <VueBadge dot variant="success" statusLabel="User is online" />
  Online
</div>

Count Badges

For live-updating counts (like notifications), use the live prop:

Vue
vue
<VueBadge
  :value="notificationCount"
  :max="99"
  variant="danger"
  live="polite"
  statusLabel="unread notifications"
/>

Variant Guide

Color Variants

  • default - Neutral dark background (default)
  • success - Green for positive status
  • info - Blue for informational status
  • warning - Yellow for warning status
  • danger - Red for error/alert status
  • neutral - Light gray for subtle badges

Size Variants

  • xs - Extra small (ideal for icon overlays)
  • sm - Small (good for inline text)
  • md - Medium (default size)

Dot Badges

Dot badges are small circular indicators perfect for status:

Vue
vue
<VueBadge dot variant="success" statusLabel="Available" />
<VueBadge dot variant="warning" statusLabel="Away" />
<VueBadge dot variant="danger" statusLabel="Busy" />
<VueBadge dot variant="info" statusLabel="In a meeting" />

Common Patterns

Notification Badge on Button

Vue
vue
<VueButton bordered variant="primary" shape="capsule">
  Notifications
  <VueBadge variant="danger" size="sm" style="margin-left: var(--ag-space-1);">
    99+
  </VueBadge>
</VueButton>

Badge on Icon

Vue
vue
<div style="position: relative; display: inline-block;">
  <VueIcon size="24">
  </VueIcon>
  <VueBadge
    variant="danger"
    size="xs"
    style="position: absolute; top: -6px; right: -7px;"
  >
    3
  </VueBadge>
</div>

Status Indicators

Vue
vue
<div style="display: flex; flex-direction: column; gap: 1rem;">
  <div style="display: flex; align-items: center; gap: 0.5rem;">
    <VueBadge dot variant="success" statusLabel="User is online" />
    Online
  </div>
  <div style="display: flex; align-items: center; gap: 0.5rem;">
    <VueBadge dot variant="warning" statusLabel="User is away" />
    Away
  </div>
  <div style="display: flex; align-items: center; gap: 0.5rem;">
    <VueBadge dot variant="danger" statusLabel="User is busy" />
    Busy
  </div>
</div>

CSS Shadow Parts

Shadow Parts allow you to style internal elements of the badge from outside the shadow DOM using the ::part() CSS selector.

PartDescription
ag-badgeThe internal <span> element

Customization Example

css
.custom-gradient-badge::part(ag-badge) {
  background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
  color: white;
  font-weight: 600;
  padding: 0.5rem 1rem;
}

.custom-outline-badge::part(ag-badge) {
  background: transparent;
  color: #764ba2;
  border: 2px solid #764ba2;
}

.custom-minimal-badge::part(ag-badge) {
  background: #f9fafb;
  color: #6b7280;
  border-radius: 6px;
  font-size: 0.85rem;
  padding: 0.25rem 0.75rem;
}