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
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
BadgePropsBadgeSizeBadgeAppearanceBadgeVariant
Basic Usage
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,
Alertor 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.
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.
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.
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.
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”.
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.
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.
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
Badge- short label or count content
Valid Composition Patterns
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.