IndicatorBadge
The IndicatorBadge overlays a visual indicator (badge with count or dot) at a corner of wrapped content to communicate notifications alerts.
Quick Start
- Installation
npm install @adaptavant/eds-core- Import
import { IndicatorBadge } from '@adaptavant/eds-core';
Basic Usage
Use IndicatorBadge to overlay indicators (counts or dots) on interactive elements such as an IconButton. The label prop is required to describe the indicator for screen readers.
NOTE: The count is displayed only when it’s greater than 0, and it shows 99+ when the count exceeds 99.
<Box className="flex items-center gap-6">
<IndicatorBadge
count={5}
label="5 unread notifications"
>
{({ childProps }) => (
<IconButton
icon={NotificationsIcon}
aria-label="notifications"
{...childProps} // must spread childProps onto the wrapped element.
/>
)}
</IndicatorBadge>
{/* In this example, the count exceeds 99. */}
<IndicatorBadge
count={150}
label="More than 99 unread notifications"
>
{({ childProps }) => (
<IconButton
icon={ChatIcon}
aria-label="messages"
{...childProps}
/>
)}
</IndicatorBadge>
</Box>
Size
The size prop controls the badge dimensions. When hasDot is true, the size is ignored because dots use a fixed size.
<Box className="flex items-center gap-6">
<IndicatorBadge
count={5}
size="small"
label="5 unread notifications"
>
{({ childProps }) => (
<IconButton
icon={NotificationsIcon}
aria-label="notifications"
{...childProps}
/>
)}
</IndicatorBadge>
<IndicatorBadge
count={5}
size="standard"
label="5 unread notifications"
>
{({ childProps }) => (
<IconButton
icon={NotificationsIcon}
aria-label="notifications"
{...childProps}
/>
)}
</IndicatorBadge>
</Box>
Variant
IndicatorBadge uses the same variants as Badge (neutral, positive, critical, caution) with Primary (solid) and Secondary (light) options.
<Box className="flex items-center gap-4">
<IndicatorBadge
count={9}
variant="criticalPrimary"
label="9 urgent notifications"
>
{({ childProps }) => (
<IconButton
icon={NotificationsIcon}
aria-label="notifications"
{...childProps}
/>
)}
</IndicatorBadge>
<IndicatorBadge
count={5}
variant="criticalSecondary"
label="5 unread conversations"
>
{({ childProps }) => (
<IconButton
icon={ChatIcon}
aria-label="tasks"
{...childProps}
/>
)}
</IndicatorBadge>
</Box>
These two show the critical variants; see BadgeVariants for all available options.
Placement
Position the indicator at any of the four corners using the placement prop.
<Box className="flex items-center gap-8">
<Box className="flex flex-col items-center gap-2">
<IndicatorBadge
count={30}
placement="topLeft"
label="30 unread messages"
>
{({ childProps }) => (
<IconButton
icon={ChatIcon}
aria-label="messages"
{...childProps}
/>
)}
</IndicatorBadge>
<Text className="text-body-12">topLeft</Text>
</Box>
<Box className="flex flex-col items-center gap-2">
<IndicatorBadge
count={30}
placement="topRight"
label="30 unread messages"
>
{({ childProps }) => (
<IconButton
icon={ChatIcon}
aria-label="messages"
{...childProps}
/>
)}
</IndicatorBadge>
<Text className="text-body-12">topRight (default)</Text>
</Box>
<Box className="flex flex-col items-center gap-2">
<IndicatorBadge
count={30}
placement="bottomLeft"
label="30 unread messages"
>
{({ childProps }) => (
<IconButton
icon={ChatIcon}
aria-label="messages"
{...childProps}
/>
)}
</IndicatorBadge>
<Text className="text-body-12">bottomLeft</Text>
</Box>
<Box className="flex flex-col items-center gap-2">
<IndicatorBadge
count={30}
placement="bottomRight"
label="30 unread messages"
>
{({ childProps }) => (
<IconButton
icon={ChatIcon}
aria-label="messages"
{...childProps}
/>
)}
</IndicatorBadge>
<Text className="text-body-12">bottomRight</Text>
</Box>
</Box>
Visibility Control
Use isVisible to control whether the indicator appears. When isVisible={false}, the count or dot is hidden, but the child element still renders normally.
const [isVisible, setIsVisible] = React.useState('true');
return (
<Box className="flex flex-col items-center gap-4">
<IndicatorBadge
count={5}
isVisible={isVisible === 'true'}
label="5 unread notifications"
>
{({ childProps }) => (
<IconButton
icon={NotificationsIcon}
aria-label="notifications"
{...childProps}
/>
)}
</IndicatorBadge>
<RadioGroup
legend="Toggle isVisible prop"
name="visibility"
onChange={setIsVisible}
value={isVisible}
>
<Radio label="true" value="true" />
<Radio label="false" value="false" />
</RadioGroup>
</Box>
);
Dot Indicator
Set hasDot={true} to display a simple dot indicator instead of a badge with a count. When hasDot is true, it takes priority over any count value; even if a count is provided, only the dot will be displayed.
<IndicatorBadge
hasDot
variant="criticalPrimary"
label="Has new updates"
>
{({ childProps }) => (
<IconButton
icon={NotificationsIcon}
aria-label="notifications"
{...childProps}
/>
)}
</IndicatorBadge>
With NavigationBar
IndicatorBadge integrates seamlessly with the NavigationBar to show notification counts on navigation items. Below is an example of that use case.
<NavigationBar>
<NavigationBarItem
href="#calendar"
icon={() => <CalDynamicIcon>{new Date().getDate()}</CalDynamicIcon>}
label="Calendar"
/>
<NavigationBarItem
href="#services"
icon={() => (
<IndicatorBadge
count={12}
label="12 unread notifications"
variant="criticalPrimary"
>
{({ childProps }) => <ServicesIcon {...childProps} />}
</IndicatorBadge>
)}
label="Services"
/>
<NavigationBarItem
href="#customers"
icon={CustomerIcon}
label="Customers"
/>
<NavigationBarItem
href="#payments"
icon={MoneyIcon}
label="Payments"
/>
</NavigationBar>
API Reference
IndicatorBadge
| Prop | Type | Description | Default |
|---|---|---|---|
children | (props: { childProps }) => React.ReactNode | Render a function that receives childProps. Spread childProps onto the wrapped element to ensure accessibility and proper component functionality. | _ |
label | string | Screen reader text describing the indicator (e.g., "5 unread notifications"). | _ |
count? | number | Numeric count displayed in the badge. The count displays only when count > 0, and when it exceeds 99 it shows "99+". | _ |
variant? | 'neutralPrimary' | 'neutralSecondary' | 'criticalPrimary' | 'criticalSecondary' | 'positivePrimary' | 'positiveSecondary' | 'cautionPrimary' | 'cautionSecondary' | Visual variant applied to indicator. | 'neutralPrimary' |
placement? | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | Position of the indicator relative to the wrapped content. | 'topRight' |
hasDot? | boolean | When true, renders a small dot indicator instead of a count badge. Takes priority over count. | false |
size? | 'standard' | 'small' | Size of the indicator (for count badges). | 'small' |
isVisible? | boolean | Controls the visibility of the indicator. When false, neither the count nor dot will be displayed. | true |
Style API
Our design system components include style props that allow you to easily customize different parts of each component to match your design needs.
Please refer to the Style API documentation for more insights.
IndicatorBadge parts
Customize the appearance of IndicatorBadge using the classNames or styles props to target specific parts.
<Box className="flex items-center gap-6">
<IndicatorBadge
count={5}
label="5 notifications with custom styling"
classNames={{
statusBadge: 'bg-palette-pink-background-active text-accent',
badgeWrapper: 'border-4 border-solid border-palette-blue-border'
}}
>
{({ childProps }) => (
<IconButton
icon={NotificationsIcon}
aria-label="notifications"
{...childProps}
/>
)}
</IndicatorBadge>
<IndicatorBadge
hasDot
classNames={{
statusDot: 'bg-palette-pink-background-active text-accent border-2 border-solid border-palette-blue-border',
}}
>
{({ childProps }) => (
<IconButton
icon={NotificationsIcon}
aria-label="notifications"
{...childProps}
/>
)}
</IndicatorBadge>
</Box>