Badge
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
Live Preview
Variants
Sizes
Count Badges
Dot Badges
Status Indicators
Positioning Badges
Inside Buttons (as content)
Absolute Position
Badges with Icon
Button Icon with Badge
CSS Parts Customization
Customize badge appearance using CSS Shadow Parts without breaking encapsulation.
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>
);
}
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:
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add BadgeThe 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
<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
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)
<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
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'success' | 'info' | 'warning' | 'danger' | 'neutral' | 'default' | Visual color variant |
size | 'xs' | 'sm' | 'md' | 'md' | Size of the badge |
dot | boolean | false | Render as a small circular dot (for status indicators) |
value | number | null | null | Numeric value to display |
max | number | 99 | Maximum value before showing "+" suffix (e.g., "99+") |
interactive | boolean | false | Make badge clickable/interactive |
statusLabel | string | null | null | ARIA label for status badges (especially important for dot badges) |
live | 'off' | 'polite' | 'assertive' | 'off' | ARIA live region politeness setting for dynamic count updates |
hiddenFromAT | boolean | false | Hide from assistive technologies |
Events
| Event | Detail | Description |
|---|---|---|
badge:click (Vue: @badge:click, React: onBadgeClick) | CustomEvent | Emitted 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-labelsupport viastatusLabelprop for meaningful descriptionsaria-liveregions for dynamic count updates (configure withliveprop)- Role
buttonfor 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
<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
<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
<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
<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
<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
<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.
| Part | Description |
|---|---|
ag-badge | The internal <span> element |
Customization Example
.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;
}