Skip to content
v2.5.0
English
Русский
Documentation

Badge

Badge is a compact status or categorization label for counts, states, and small metadata.
Active
Beta
badge.tsx · 6 lines
import { Badge } from '@vega-ui/react';

<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
  <Badge variant='success'>Active</Badge>
  <Badge variant='warning' appearance='surface'>Beta</Badge>
</div>
Browser support
Newly available 2024
  • Chrome 125
  • Edge 125
  • Firefox 128
  • Safari 18
  • Safari on iOS 18
Bundle size
Tested in
8 tests

Summary

Badge is a compact status or categorization label for counts, states, and small metadata. It is for small inline status cues, not for full feedback messaging.

Imports

import {
  Badge,
  type BadgeProps,
  type BadgeSize,
  type BadgeAppearance,
  type BadgeVariant,
} from '@vega-ui/react';

Exported Types

  • BadgeProps
  • BadgeSize
  • BadgeAppearance
  • BadgeVariant

Basic Usage

basic-usage.tsx · 22 lines
import { Badge, Text } from '@vega-ui/react';

const releases = [
  { version: 'v2.8.0', date: 'Nov 3, 2026', status: 'Live', variant: 'success' },
  { version: 'v2.8.0-rc.2', date: 'Oct 30, 2026', status: 'Rolling back', variant: 'warning' },
  { version: 'v2.7.4', date: 'Oct 21, 2026', status: 'Failed', variant: 'error' },
  { version: 'v2.7.3', date: 'Oct 14, 2026', status: 'Archived', variant: 'info' },
];

export default function BasicUsage() {
  return (
    <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'grid', gap: 'var(--spacing-6)', width: '100%', maxWidth: 420 }}>

Variants

  • Sizes: xs, sm, md, lg, xl
  • Appearances: fill, outline, ghost, surface
  • Variants: success, error, warning, info

Edge Cases

  • Keep badge copy short; it is not a pill-shaped paragraph container.
  • Use semantic variants consistently across the product.
  • Custom string tokens only work if the corresponding styles exist.
  • If the user needs explanation rather than a terse label, Alert or surrounding body copy is usually the better pattern.

Common Mistakes

  • Putting long sentences into a badge.
  • Using a badge as the only indicator of status.
  • Inventing custom variant names without adding matching styles.

Examples

Basic

Basic: release statuses

Each status maps to a variant, and the text always names the state, so the meaning does not depend on color alone.

basic-usage.tsx · 22 lines
import { Badge, Text } from '@vega-ui/react';

const releases = [
  { version: 'v2.8.0', date: 'Nov 3, 2026', status: 'Live', variant: 'success' },
  { version: 'v2.8.0-rc.2', date: 'Oct 30, 2026', status: 'Rolling back', variant: 'warning' },
  { version: 'v2.7.4', date: 'Oct 21, 2026', status: 'Failed', variant: 'error' },
  { version: 'v2.7.3', date: 'Oct 14, 2026', status: 'Archived', variant: 'info' },
];

export default function BasicUsage() {
  return (
    <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'grid', gap: 'var(--spacing-6)', width: '100%', maxWidth: 420 }}>

Basic: metadata next to a heading

Low-emphasis outline and surface badges at size='xs' mark a feature as Beta or plan-limited without competing with the heading. The badge sits next to the heading, not inside it, so the heading text stays clean for screen readers and the outline.

heading-flags.tsx · 22 lines
import { Badge, Heading, Text } from '@vega-ui/react';

export default function HeadingFlags() {
  return (
    <div style={{ display: 'grid', gap: 'var(--spacing-10)', width: '100%', maxWidth: 520 }}>
      <div style={{ display: 'grid', gap: 'var(--spacing-2)' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-4)' }}>
          <Heading as='h3' size={4} fontWeight={600}>Usage-based billing</Heading>
          <Badge size='xs' variant='info' appearance='outline'>Beta</Badge>
        </div>
        <Text size={2} style={{ color: 'var(--label-secondary)' }}>Charge customers for API calls, seats or storage.</Text>
      </div>

Controlled/Stateful

Controlled/Stateful: deployment status from state

The label and the variant are derived from the current stage, and the badge sits in a role='status' region so each change is announced.

deploy-status.tsx · 44 lines
import { useEffect, useState } from 'react';
import { Badge, Button, Text } from '@vega-ui/react';

type Stage = 'idle' | 'building' | 'deploying' | 'live';

const stages: Record<Stage, { label: string; variant: string }> = {
  idle: { label: 'Not deployed', variant: 'info' },
  building: { label: 'Building', variant: 'warning' },
  deploying: { label: 'Deploying', variant: 'warning' },
  live: { label: 'Live', variant: 'success' },
};

Layout/Overlay

Layout/Overlay: status column in a table

Badges stay on one line inside table cells; long customer names wrap in their own column instead. The table scrolls horizontally on narrow screens.

invoices-table.tsx · 47 lines
import { Badge, Table, TableBody, TableData, TableHead, TableHeading, TableRow, Text } from '@vega-ui/react';

const statusVariant: Record<string, string> = {
  Paid: 'success',
  Overdue: 'error',
  Draft: 'info',
  'Partially paid': 'warning',
};

const invoices = [
  { id: 'INV-2051', customer: 'Northwind Traders', amount: '$4,200.00', status: 'Paid' },
  { id: 'INV-2050', customer: 'Contoso Pharmaceuticals International', amount: '$12,980.50', status: 'Overdue' },

Error

Error: failing status with the reason linked

The error badge says what is wrong in one word, and the full reason is a separate text linked to the retry button with aria-describedby. A successful retry switches the badge to “Healthy”.

webhook-health.tsx · 36 lines
import { useState } from 'react';
import { Badge, Button, Text } from '@vega-ui/react';

export default function WebhookHealth() {
  const [failing, setFailing] = useState(true);
  const [retrying, setRetrying] = useState(false);

  const retry = () => {
    setRetrying(true);
    setTimeout(() => {
      setRetrying(false);
      setFailing(false);

Edge

Edge: count with a cap and a full accessible label

Counts above 99 are shown as “99+”, zero hides the badge, and the exact number is read by screen readers through VisuallyHidden while the short visual text is aria-hidden.

unread-count.tsx · 33 lines
import { useState } from 'react';
import { Badge, Button, Text, VisuallyHidden } from '@vega-ui/react';

const max = 99;

export default function UnreadCount() {
  const [count, setCount] = useState(7);

  let shown = String(count);
  if (count > max) shown = `${max}+`;

  let label = `${count} unread messages`;

Edge: long and non-Latin labels in a narrow container

Badges do not wrap their text. A long tag needs max-width, a shrinkable flex item and an ellipsis, with the full text in title; Cyrillic and CJK labels keep the same height.

long-labels.tsx · 30 lines
import { Badge, Text } from '@vega-ui/react';

const tags = [
  'enterprise-customer-success-escalation-q4',
  'Требует проверки юристом',
  '优先处理',
  'β-tester',
];

export default function LongLabels() {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr)', gap: 'var(--spacing-6)', boxSizing: 'border-box', width: '100%', maxWidth: 280, padding: 'var(--spacing-8)', border: '1px solid var(--separator-opaque)', borderRadius: 'var(--radius-4)', background: 'var(--surface-primary)' }}>

Anatomy

Overview

Badge is a single compact surface for short status, category, or count text.

Required Parts

Badge

Required. Owns size, appearance, and semantic variant styling.

Optional Parts

Badge does not expose public child parts.

Composition Order

  1. Badge
  2. short label or count content

Valid Composition Patterns

basic-usage.tsx · 22 lines
import { Badge, Text } from '@vega-ui/react';

const releases = [
  { version: 'v2.8.0', date: 'Nov 3, 2026', status: 'Live', variant: 'success' },
  { version: 'v2.8.0-rc.2', date: 'Oct 30, 2026', status: 'Rolling back', variant: 'warning' },
  { version: 'v2.7.4', date: 'Oct 21, 2026', status: 'Failed', variant: 'error' },
  { version: 'v2.7.3', date: 'Oct 14, 2026', status: 'Archived', variant: 'info' },
];

export default function BasicUsage() {
  return (
    <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'grid', gap: 'var(--spacing-6)', width: '100%', maxWidth: 420 }}>

Invalid Composition Patterns

Long explanatory copy inside a badge

Badges are for short metadata, not full messages.

Badge used as the only status communication

If the status matters, surrounding copy or structure should still explain it.