A notification badge component for displaying counts, icons, or status indicators. Wraps children and positions the badge indicator relative to them.
Display a count badge on any element. The badge center sits exactly on the corner of the child element.
<Badge count={5} aria-label="5 notifications">
<Avatar user={user} />
</Badge>
<Badge count={12} aria-label="12 messages">
<Button label="Messages" />
</Badge>Omit count and icon to render a small dot indicator. Useful for presence or unread status.
{/* Empty badge - just a dot indicator */}
<Badge status="danger" aria-label="Unread">
<Icon icon="mail" />
</Badge>
<Badge status="success" aria-label="Online">
<Avatar user={user} />
</Badge>Display an icon instead of a count.
<Badge icon="bell" status="danger" aria-label="New alerts"> <Button>Notifications</Button> </Badge>
Position the badge on any corner. The badge center aligns with the corner point.
top-right (default)
top-left
bottom-right
bottom-left
center
<Badge count={1} position="top-right" aria-label="...">
<Avatar user={user} />
</Badge>
<Badge count={2} position="top-left" aria-label="...">
<Avatar user={user} />
</Badge>
<Badge count={3} position="bottom-right" aria-label="...">
<Avatar user={user} />
</Badge>
<Badge count={4} position="bottom-left" aria-label="...">
<Avatar user={user} />
</Badge>
{/* Center - useful when badge is the main focus */}
<Badge count={5} position="center" aria-label="...">
<Avatar user={user} />
</Badge>Use the shape prop to control the badge shape. Without a shape prop, the badge renders as a pill that expands to fit content.
pill (default)
circle (0)
triangle (3)
square (4)
pentagon (5)
{/* Pill shape (default) - expands to fit content */}
<Badge count={123} aria-label="123 items">...</Badge>
{/* Circle */}
<Badge count={3} shape={0} aria-label="3 items">...</Badge>
{/* Triangle */}
<Badge count={3} shape={3} aria-label="3 items">...</Badge>
{/* Square */}
<Badge count={3} shape={4} aria-label="3 items">...</Badge>
{/* Pentagon */}
<Badge count={3} shape={5} aria-label="3 items">...</Badge>Shapes can also be used without content to create shaped dot indicators.
pill (default)
circle
triangle
square
pentagon
{/* Empty shaped badges - no count or icon */}
<Badge status="danger" shape={0} aria-label="Alert">...</Badge>
<Badge status="danger" shape={3} aria-label="Alert">...</Badge>
<Badge status="danger" shape={4} aria-label="Alert">...</Badge>Empty shapes with the hollow variant for subtle indicators.
pill hollow
circle hollow
square hollow
When a shape is specified, counts over 9 display as "9+" in a circle. Pill shapes expand to show the full number.
pill: shows 123
circle: shows 9+
square: shows 9+
Use the variant prop to switch between solid and hollow styles. Both variants can display counts, icons, or be empty.
solid with count
solid empty
hollow with count
hollow empty
{/* Solid - filled background */}
<Badge count={5} variant="solid" status="info" aria-label="5">
<Avatar user={user} />
</Badge>
{/* Hollow - outlined style */}
<Badge count={5} variant="hollow" status="info" aria-label="5">
<Avatar user={user} />
</Badge>Badge integrates with the Status system for semantic coloring.
neutral
info
success
warning
danger
Badge automatically matches its outer border color to the container background using ContainerContext. This provides visual separation between the badge and its surroundings.
<Container>
<Badge count={3} status="danger" aria-label="3 items">
<Avatar user={user} />
</Badge>
</Container>
<Container status="info">
<Badge count={5} status="danger" aria-label="5 items">
<Avatar user={user} />
</Badge>
</Container>Use the show prop to control badge visibility. Note that count=0 displays "0" and does not auto-hide.
show=true
show=false
count=0 (visible)
{/* Hidden badge */}
<Badge count={5} show={false} aria-label="5 notifications">
<Avatar user={user} />
</Badge>
{/* count=0 displays "0" */}
<Badge count={0} aria-label="0 items">
<Avatar user={user} />
</Badge>Add an onClick handler to make the badge itself interactive, separate from the wrapped children. Supports keyboard navigation (Enter/Space).
<Badge count={3} aria-label="3 messages" onClick={() => openMessages()}>
<Icon icon="chat" />
</Badge>| Name | Type | Default | Description |
|---|---|---|---|
children* | JSXElement | - | Element to wrap with badge |
aria-label* | string | - | Accessibility label for screen readers |
count | number | undefined | Number to display (takes precedence over icon). Capped at 9+ for polygon shapes. |
icon | string | undefined | Icon to display (ignored if count provided) |
position | "top-right" | "top-left" | "bottom-right" | "bottom-left" | "center" | "top-right" | Position of badge. Corner positions place badge on edges; center places badge in the middle of the child. |
shape | 0 | 3 | 4 | 5 | undefined | Number of vertices (0=circle, 3=triangle, 4=square, 5=pentagon). If omitted, uses pill shape. |
variant | "solid" | "hollow" | "solid" | Visual variant |
status | Status | "neutral" | Status color theme (success, danger, warning, info, neutral) |
show | boolean | true | Controls badge visibility |
onClick | () => void | undefined | Click handler for the badge itself |
rootStyles | StyleXStyles | undefined | Custom StyleX styles for the wrapper element |
badgeStyles | StyleXStyles | undefined | Custom StyleX styles for the badge indicator itself. Useful for custom positioning. |
inline | boolean | false | Use inline display for text flow (e.g., in SmartStrings). Default is inline-flex for proper box model. |
* Required prop
Badge appearance can be customized via theme variables in themeDetails:
// In theme.stylex.ts
export const themeDetails = stylex.defineVars({
// Badge sizing
badgeSize: themeSizing.spaceM,
badgeDotSize: `calc(${themeSizing.spaceXS} * 2)`,
badgeFontSize: themeSizing.font0,
// Badge padding
badgePaddingInline: `calc(${themeSizing.spaceXS} * 0.75)`,
badgePaddingBlock: `calc(${themeSizing.spaceXS} * 0.25)`,
// Badge borders
badgeBorderWidth: `calc(${themeSizing.spaceXS} * 0.5)`,
badgeInnerBorderWidth: `calc(${themeSizing.spaceXS} * 0.4)`,
// Badge icon
badgeIconSize: `calc(${themeSizing.spaceM} * 0.65)`,
});aria-label - Required prop for screen reader accessibility
role="status" - Badge uses status role to indicate it contains live content
Clickable badges support keyboard navigation with Enter and Space keys
Interactive badges receive focus with tabIndex when onClick is provided