Badge
A short status label in three variants across six tones. It renders on the server and ships no JavaScript.
server - 0 KB
Badge
server - 0 KBA short status label in three variants across six tones. It renders on the server and ships no JavaScript.
Paid
Try it
variant
tone
size
The code
badge.tsx
import { Badge } from 'topclassui/badge'
<Badge>Paid</Badge>Badge has no ARIA role: the text carries the meaning, colour never does alone.
Every state
3 statesSolidSoftOutline
Import from the package
topclassui/badge
import { Badge } from 'topclassui/badge'Install once:npm i topclassui@beta zod
Examples
- For a short status beside the thing it describes: Paid, Pending, Draft, a count. It is a label, not a control; for something the user can remove or press, use a Tag or a Button.
- A long label truncates to its container with an ellipsis instead of wrapping.
BadgeSkeletonholds its place at the same height while data loads; give it thesizeof the badge it stands in for.size="custom"emits no size classes, soclassNamesets the padding and the type step.
with-icon
PaidPendingOverdue
with-icon.tsx
import { checkCircle } from 'topclassui/icons/check-circle'
import { Svg } from 'topclassui/svg'
import { Badge } from 'topclassui/badge'
/** The docs sample: the icon is decoration, the word carries the status. */
export default function Demo() {
return (
<div className="flex flex-wrap items-center gap-2">
<Badge tone="success" variant="soft">
<Svg icon={checkCircle} />
Paid
</Badge>
<Badge tone="warning" variant="soft">Pending</Badge>
<Badge tone="danger" variant="solid">Overdue</Badge>
</div>
)
}
variants
SolidSoftOutline
variants.tsx
import { Badge } from 'topclassui/badge'
export default function Demo() {
return (
<div className="flex flex-wrap items-center gap-3">
<Badge variant="solid">Solid</Badge>
<Badge variant="soft">Soft</Badge>
<Badge variant="outline">Outline</Badge>
</div>
)
}
tones
PrimaryNeutralSuccessWarningDangerInfo
PrimaryNeutralSuccessWarningDangerInfo
PrimaryNeutralSuccessWarningDangerInfo
tones.tsx
import { Badge } from 'topclassui/badge'
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<div className="flex flex-wrap items-center gap-3">
<Badge variant="solid" tone="primary">Primary</Badge>
<Badge variant="solid" tone="neutral">Neutral</Badge>
<Badge variant="solid" tone="success">Success</Badge>
<Badge variant="solid" tone="warning">Warning</Badge>
<Badge variant="solid" tone="danger">Danger</Badge>
<Badge variant="solid" tone="info">Info</Badge>
</div>
<div className="flex flex-wrap items-center gap-3">
<Badge variant="soft" tone="primary">Primary</Badge>
<Badge variant="soft" tone="neutral">Neutral</Badge>
<Badge variant="soft" tone="success">Success</Badge>
<Badge variant="soft" tone="warning">Warning</Badge>
<Badge variant="soft" tone="danger">Danger</Badge>
<Badge variant="soft" tone="info">Info</Badge>
</div>
<div className="flex flex-wrap items-center gap-3">
<Badge variant="outline" tone="primary">Primary</Badge>
<Badge variant="outline" tone="neutral">Neutral</Badge>
<Badge variant="outline" tone="success">Success</Badge>
<Badge variant="outline" tone="warning">Warning</Badge>
<Badge variant="outline" tone="danger">Danger</Badge>
<Badge variant="outline" tone="info">Info</Badge>
</div>
</div>
)
}
sizes
Extra smallSmallMediumLargeExtra large
sizes.tsx
import { Badge } from 'topclassui/badge'
export default function Demo() {
return (
<div className="flex flex-wrap items-center gap-3">
<Badge size="xs">Extra small</Badge>
<Badge size="sm">Small</Badge>
<Badge size="md">Medium</Badge>
<Badge size="lg">Large</Badge>
<Badge size="xl">Extra large</Badge>
</div>
)
}
long-label
Awaiting a second approval from the finance team before release
Awaiting a second approval from the finance team before release
Awaiting a second approval from the finance team before release
long-label.tsx
import { checkCircle } from 'topclassui/icons/check-circle'
import { Svg } from 'topclassui/svg'
import { Badge } from 'topclassui/badge'
const LONG = 'Awaiting a second approval from the finance team before release'
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<div className="w-50 rounded-box border border-line p-2" data-narrow>
<Badge>{LONG}</Badge>
</div>
<div className="w-50 rounded-box border border-line p-2" data-narrow>
<Badge variant="outline" tone="warning">
<Svg icon={checkCircle} />
{LONG}
</Badge>
</div>
<div className="w-50 rounded-box border border-line p-2" data-narrow>
<Badge variant="solid" size="xs">{LONG}</Badge>
</div>
</div>
)
}
skeleton
Small
Medium
Large
skeleton.tsx
import { Badge } from 'topclassui/badge'
import { BadgeSkeleton } from 'topclassui/badge'
/** Each skeleton on one row with the badge it stands in for, so a height mismatch shows. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<div className="flex items-center gap-3">
<BadgeSkeleton size="sm" />
<Badge size="sm">Small</Badge>
</div>
<div className="flex items-center gap-3">
<BadgeSkeleton />
<Badge>Medium</Badge>
</div>
<div className="flex items-center gap-3">
<BadgeSkeleton size="lg" />
<Badge size="lg">Large</Badge>
</div>
</div>
)
}
custom-size
The scaleYour own row
custom-size.tsx
import { Badge } from 'topclassui/badge'
export default function Demo() {
return (
<div className="flex flex-wrap items-center gap-3">
<Badge size="md">The scale</Badge>
<Badge size="custom" className="px-pad-x-xs py-pad-y-xs text-xs">Your own row</Badge>
</div>
)
}
In Arabic, right to left
مدفوعقيد الانتظارمتأخرمسودة
rtl.tsx
import { checkCircle } from 'topclassui/icons/check-circle'
import { Svg } from 'topclassui/svg'
import { Badge } from 'topclassui/badge'
export default function Demo() {
return (
<div dir="rtl" lang="ar" className="flex flex-wrap items-center gap-2">
<Badge tone="success">
<Svg icon={checkCircle} />
مدفوع
</Badge>
<Badge tone="warning">قيد الانتظار</Badge>
<Badge tone="danger" variant="solid">متأخر</Badge>
<Badge variant="outline">مسودة</Badge>
</div>
)
}
Props
Keyboard and accessibility
Nothing to operate: it is not interactive on its own.
- Badge is not focusable and has no role, so a screen reader reads its text as part of the sentence around it.
- Write the status in words: Paid, Overdue. A tone alone says nothing to someone who cannot see the colour.
- An icon beside the text is decoration; the word carries the status.
Right to left
The icon and the text swap sides with the reading direction, and a cut label keeps its ellipsis at the end of its own direction.
Server and client
Renders on the server and ships no JavaScript.
Files: index.tsx.
On the chip: server - 0 KB.