Badge
A compact label for counts, statuses, and short metadata. Supports numeric overflow capping, a dot-only indicator, an optional icon slot, and all color themes.
Features
- 🎨 5 Variants: solid, flat, bordered, outline, frost
- 🌈 6 Semantic Colors: primary, secondary, info, success, warning, error
- 📏 3 Sizes: sm, md, lg
- 🔢 Count Mode: display numeric counts with an optional max cap (e.g.
99+) - 🔴 Dot Mode: minimal dot indicator when no label needed- 📌 Overlay Mode:
anchorprop pins the badge to a corner of any slotted content- 🔧 Icon Slot: prepend an icon inside the badge
Source Code
View Source Code
import { computed, defineComponent, html } from '@vielzeug/craftit';
import type { ComponentSize, RoundedSize, ThemeColor, VisualVariant } from '../../types';
import { colorThemeMixin, frostVariantMixin, roundedVariantMixin, sizeVariantMixin } from '../../styles';
import componentStyles from './badge.css?inline';
type BadgeVariant = Extract<VisualVariant, 'solid' | 'flat' | 'bordered' | 'outline' | 'frost'>;
/** Badge component properties */
export type BitBadgeProps = {
/**
* When set, switches to overlay mode: the host becomes `position:relative`
* and the badge pins to a corner over the slotted content.
* Value controls which corner: 'top-end' (default) | 'top-start' | 'bottom-end' | 'bottom-start'
*/
anchor?: 'top-end' | 'top-start' | 'bottom-end' | 'bottom-start';
/** Accessible label for assistive technology. Recommended for count-only and dot mode. */
ariaLabel?: string;
/** Theme color */
color?: ThemeColor;
/** Numeric count to display */
count?: number;
/** Render as a small dot with no label */
dot?: boolean;
/** Max count — displays "<max>+" when count exceeds this value */
max?: number;
/** Border radius override */
rounded?: RoundedSize;
/** Badge size */
size?: ComponentSize;
/** Visual style variant */
variant?: BadgeVariant;
};
/**
* A compact badge/chip for counts, statuses, and labels.
* Supports numeric counts with overflow, dot mode, and icon slots.
*
* @element bit-badge
*
* @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'
* @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'frost'
* @attr {string} size - Component size: 'sm' | 'md' | 'lg'
* @attr {number} count - Numeric count to display
* @attr {number} max - Max count before showing "<max>+"
* @attr {boolean} dot - Render as a dot indicator (no text)
* @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'full' etc.
*
* @slot - Badge label text
* @slot icon - Icon displayed before the label
* @slot target - Element the badge is anchored to (used with the anchor attribute)
*
* @cssprop --badge-bg - Badge background color
* @cssprop --badge-color - Badge text color
* @cssprop --badge-border-color - Badge border color
* @cssprop --badge-radius - Border radius
* @cssprop --badge-font-size - Font size
* @cssprop --badge-font-weight - Font weight
* @cssprop --badge-padding-x - Horizontal padding
* @cssprop --badge-padding-y - Vertical padding
* @cssprop --badge-gap - Gap between icon and label
*
* @example
* ```html
* <bit-badge color="primary">New</bit-badge>
* <bit-badge color="error" count="5"></bit-badge>
* <bit-badge color="error" count="120" max="99"></bit-badge>
* <bit-badge color="success" dot></bit-badge>
* <bit-badge color="warning" variant="flat">Beta</bit-badge>
* ```
*/
export const BADGE_TAG = defineComponent<BitBadgeProps>({
props: {
anchor: { default: undefined },
ariaLabel: { default: undefined },
color: { default: undefined },
count: { default: undefined },
dot: { default: false },
max: { default: undefined },
rounded: { default: undefined },
size: { default: undefined },
variant: { default: undefined },
},
setup({ props }) {
const label = computed(() => {
const count = props.count.value != null ? Number(props.count.value) : undefined;
const max = props.max.value != null ? Number(props.max.value) : undefined;
if (count === undefined || Number.isNaN(count)) return undefined;
if (max !== undefined && !Number.isNaN(max) && count > max) return `${max}+`;
return String(count);
});
return html`<span class="badge" part="badge" aria-label=${() => props.ariaLabel.value}>
<slot name="icon"></slot>
<span ?hidden=${() => label.value == null}>${() => label.value}</span>
<slot ?hidden=${() => label.value != null}></slot>
</span>
<slot name="target"></slot>`;
},
styles: [
colorThemeMixin,
roundedVariantMixin,
frostVariantMixin('.badge'),
sizeVariantMixin({
lg: { '--_padding-x': 'var(--size-2-5)', '--_padding-y': 'var(--size-1)', fontSize: 'var(--text-sm)' },
md: { '--_padding-x': 'var(--size-2)', '--_padding-y': 'var(--size-0-5)', fontSize: 'var(--text-xs)' },
sm: { '--_padding-x': 'var(--size-1-5)', '--_padding-y': 'var(--size-px)', fontSize: 'var(--text-xs)' },
}),
componentStyles,
],
tag: 'bit-badge',
});Basic Usage
<bit-badge color="primary">New</bit-badge>
<script type="module">
import '@vielzeug/buildit/badge';
</script>Visual Options
Variants
The badge comes with five visual variants to match different levels of emphasis.
Frost Variant
Modern frost effect with backdrop blur that adapts based on color:
- Without color: Subtle canvas-based frost overlay
- With color: Frosted glass effect with colored tint
Best Used With
Frost variant works best when placed over colorful backgrounds or images to showcase the blur and transparency effects.
Colors
Six semantic colors for different contexts.
Sizes
Three sizes for different contexts.
Count Badge
Use count and max for numeric notification badges. When count exceeds max the label renders as {max}+.
Dot Indicator
Use dot for a minimal presence indicator with no label.
With Icon
Use the icon slot to prepend an SVG or icon font glyph.
Rounded Variants
Using Badges with Other Components
Badges work great when combined with other components to show counts, status, or notifications.
Overlay / Notification Badge
Use the anchor prop with the target slot to pin a badge to the corner of any element. The host becomes position: relative and the badge is positioned absolutely at the specified corner.
Four corner positions are available:
anchor value | Corner |
|---|---|
top-end (default) | Top-right |
top-start | Top-left |
bottom-end | Bottom-right |
bottom-start | Bottom-left |
With Icons
Combine badges with icon buttons for compact notification indicators.
Multiple Badges
Stack multiple badges to show different types of information.
API Reference
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
variant | 'solid' | 'flat' | 'bordered' | 'outline' | 'frost' | 'solid' | Visual style variant |
color | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error' | - | Theme color |
size | 'sm' | 'md' | 'lg' | 'md' | Badge size |
rounded | 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full' | 'full' | Border radius |
count | number | - | Numeric count to display |
max | number | 99 | Maximum count before showing {max}+ |
dot | boolean | false | Show as a dot indicator (no label) |
anchor | 'top-end' | 'top-start' | 'bottom-end' | 'bottom-start' | — | Pin badge to a corner of the target slot content |
aria-label | string | — | Accessible label for assistive technology. Recommended for count-only and dot mode. |
Slots
| Slot | Description |
|---|---|
| (default) | Badge label text |
icon | Icon prepended inside the badge |
target | Element the badge overlays when anchor prop is set |
CSS Custom Properties
| Property | Description | Default |
|---|---|---|
--badge-bg | Background color | Theme-dependent |
--badge-color | Text / icon color | Theme-dependent |
--badge-border-color | Border color | Theme-dependent |
--badge-radius | Border radius | var(--rounded-full) |
--badge-font-size | Font size | var(--text-xs) |
--badge-font-weight | Font weight | var(--font-semibold) |
--badge-padding-x | Horizontal padding | var(--size-1-5) |
--badge-padding-y | Vertical padding | var(--size-0-5) |
--badge-gap | Gap between icon and label | var(--size-1) |
--badge-max-width | Maximum text width | 24ch |
Accessibility
The badge component follows WAI-ARIA best practices.
bit-badge
✅ Screen Readers
- Badge text content is read by screen readers as inline text.
- Count badges expose the full value (or
{max}+) as visible text that is read aloud. - Dot indicator badges and count-only badges convey meaning through color and shape alone — use the
aria-labelattribute directly onbit-badgeto provide a text description for assistive technology. - When multiple badges are present, each should have a distinct
aria-labelto distinguish them.
Best Practices
Do:
- Use count badges near buttons, nav items, or avatars to show notification totals.
- Keep badge labels very short (1–3 words). For longer status text use
bit-alert. - Use
dotwhen presence alone is enough (e.g., online indicator, unread indicator). - Use
color="error"for notification counts to draw immediate attention.
Don't:
- Use badges as the primary call-to-action; use
bit-buttonfor that. - Display lengthy sentences inside a badge.