Badge
Badges are colored text elements containing small bits of information. They’re used for labeling content, displaying metadata and/or highlighting information.
new tab
{/* Since a native span element does not know about the theme attribute, as a workaround, you
can use the spread operator to pass the theme attribute to the span element. */}
<span {...{ theme: 'badge' }}>Pending</span>
<span {...{ theme: 'badge success' }}>Confirmed</span>
<span {...{ theme: 'badge error' }}>Denied</span>
<span {...{ theme: 'badge contrast' }}>On hold</span>
Note
|
Import styles
Badge is a set of CSS classes rather than a web / Flow component.
The Badge-specific CSS classes are available as part of the Lumo theme.
To use these classes in your application, enable them in your theme’s
The |
Label
Badges should contain a label. Labels should be clear, concise, and written using sentence case. Aim for 1 to 2 words.
Icons
Badges can contain icons as well as text. Icons can be placed on either side of the text.
new tab
<VerticalLayout theme="spacing">
<HorizontalLayout theme="spacing">
<span {...{ theme: 'badge' }}>
<Icon icon="vaadin:clock" style={{ padding: 'var(--lumo-space-xs)' }} />
<span>Pending</span>
</span>
<span {...{ theme: 'badge success' }}>
<Icon icon="vaadin:check" style={{ padding: 'var(--lumo-space-xs)' }} />
<span>Confirmed</span>
</span>
<span {...{ theme: 'badge error' }}>
<Icon icon="vaadin:exclamation-circle-o" style={{ padding: 'var(--lumo-space-xs)' }} />
<span>Denied</span>
</span>
<span {...{ theme: 'badge contrast' }}>
<Icon icon="vaadin:hand" style={{ padding: 'var(--lumo-space-xs)' }} />
<span>On hold</span>
</span>
</HorizontalLayout>
<HorizontalLayout theme="spacing">
<span {...{ theme: 'badge' }}>
<span>Pending</span>
<Icon icon="vaadin:clock" style={{ padding: 'var(--lumo-space-xs)' }} />
</span>
<span {...{ theme: 'badge success' }}>
<span>Confirmed</span>
<Icon icon="vaadin:check" style={{ padding: 'var(--lumo-space-xs)' }} />
</span>
<span {...{ theme: 'badge error' }}>
<span>Denied</span>
<Icon icon="vaadin:exclamation-circle-o" style={{ padding: 'var(--lumo-space-xs)' }} />
</span>
<span {...{ theme: 'badge contrast' }}>
<span>On hold</span>
<Icon icon="vaadin:hand" style={{ padding: 'var(--lumo-space-xs)' }} />
</span>
</HorizontalLayout>
</VerticalLayout>
Note
|
Use icons sparingly
The benefit of using icons should be weighed against the visual noise it adds.
|
Icon-Only
Badges can also be used with icons without a label.
For accessibility, a tooltip and aria-label
attribute is recommended to ensure that all users can identify their meaning.
new tab
<Icon
aria-label="Confirmed"
icon="vaadin:check"
style={{ padding: 'var(--lumo-space-xs)' }}
theme="badge success"
title="Confirmed"
/>
<Icon
aria-label="Cancelled"
icon="vaadin:close-small"
style={{ padding: 'var(--lumo-space-xs)' }}
theme="badge error"
title="Cancelled"
/>
Icon-only badges should primarily be used for common recurring content with highly standardized, universally understood icons (such as a checkmark for "yes"), and for content that’s repeated, for example in lists and tables.
new tab
const renderBoolean = ({
item,
original: column,
}: {
item: any;
original: GridColumnElement<UserPermissions>;
}) => {
let icon;
let title;
let theme;
if (item[column.id]) {
icon = 'vaadin:check';
title = 'Yes';
theme = 'success';
} else {
icon = 'vaadin:close-small';
title = 'No';
theme = 'error';
}
return (
<Icon
aria-label={title}
icon={icon}
style={{ padding: 'var(--lumo-space-xs)' }}
theme={`badge ${theme}`}
title={title}
/>
);
};
return (
<Grid items={items} ref={gridRef}>
<GridColumn path="name" header="Name" />
<GridColumn id="view" header="View">
{renderBoolean}
</GridColumn>
<GridColumn id="comment" header="Comment">
{renderBoolean}
</GridColumn>
<GridColumn id="edit" header="Edit">
{renderBoolean}
</GridColumn>
</Grid>
);
Theme Variants
Badge features theme variants for different sizes, colors, and shapes. You can combine any theme variants together.
Size
Badges have two different sizes you can use: the default (normal) and small
.
Use the small
theme variant to make a badge smaller, for example when space is limited or for compact parts of the UI.
new tab
<span {...{ theme: 'badge small' }}>Pending</span>
<span {...{ theme: 'badge success small' }}>Confirmed</span>
<span {...{ theme: 'badge error small' }}>Denied</span>
<span {...{ theme: 'badge contrast small' }}>On hold</span>
Color
Badges have four different color variants: default, success
, error
, and contrast
.
The color variants can be paired with the primary
theme variant for additional emphasis.
new tab
<VerticalLayout theme="spacing">
<HorizontalLayout theme="spacing">
<span {...{ theme: 'badge ' }}>Pending</span>
<span {...{ theme: 'badge success ' }}>Confirmed</span>
<span {...{ theme: 'badge error ' }}>Denied</span>
<span {...{ theme: 'badge contrast ' }}>On hold</span>
</HorizontalLayout>
<HorizontalLayout theme="spacing">
<span {...{ theme: 'badge primary ' }}>Pending</span>
<span {...{ theme: 'badge success primary ' }}>Confirmed</span>
<span {...{ theme: 'badge error primary ' }}>Denied</span>
<span {...{ theme: 'badge contrast primary ' }}>On hold</span>
</HorizontalLayout>
</VerticalLayout>
Variant | Theme name | Usage recommendations |
---|---|---|
Normal | Default style. Recommended for informational messages. This style may be confused with a Button or link. | |
Success |
| Highlight positive outcomes, such as when a task or operation is completed. |
Error |
| Use the error theme variant to communicate alerts, failures, or warnings. |
Contrast |
| A high-contrast version that improves legibility and distinguishes the badge from the rest of the UI. Recommended for neutral badges (that don’t communicate success or errors). |
Primary |
| Used for important information and/or to draw more attention to your badge. Can be combined with all other theme variants. |
Note
|
Accessibility
Assistive technologies, such as screen readers, interpret badges solely based on their content.
Without proper context, they may end up confusing the user.
If you are using colors and icons to convey information, provide the same info via aria-label to ensure that screen readers can interpret the information.
|
Shape
Applying the pill
theme variant produces a badge with rounded corners.
It can aid in making badges and buttons more distinct from one another.
new tab
<span {...{ theme: 'badge pill' }}>Pending</span>
<span {...{ theme: 'badge success pill' }}>Confirmed</span>
<span {...{ theme: 'badge error pill' }}>Denied</span>
<span {...{ theme: 'badge contrast pill' }}>On hold</span>
Use Cases
Highlighting and Distinguishing Information
A typical use case for badges is to highlight an item’s status, for example in a Grid.
new tab
<Grid items={items}>
<GridColumn path="report" header="Report" />
<GridColumn header="Due date">
{({ item: report }) => <span>{dateFormatter.format(new Date(report.due))}</span>}
</GridColumn>
<GridColumn path="assignee" header="Assignee" />
<GridColumn header="Status">
{({ item: report }) => {
let title: string;
let theme: string;
switch (report.status) {
case ReportStatus.COMPLETED:
title = 'Completed';
theme = 'success';
break;
case ReportStatus.IN_PROGRESS:
title = 'In progress';
theme = '';
break;
case ReportStatus.CANCELLED:
title = 'Cancelled';
theme = 'error';
break;
default:
title = 'On hold';
theme = 'contrast';
break;
}
return <span {...{ theme: `badge ${theme} primary` }}>{title}</span>;
}}
</GridColumn>
</Grid>
They are also often used for displaying metadata tags.
Interactive Content
Badges can house interactive content such as Anchors and Buttons. For example, Badges that highlight active filters might contain a "Clear" Button which removes the associated filter.
new tab
return (
<VerticalLayout theme="spacing" ref={layoutRef}>
<ComboBox label="Profession" items={items} onChange={onChange} />
<HorizontalLayout style={{ flexWrap: 'wrap' }} theme="spacing">
{selectedProfessions.map((profession) => (
<span key={profession} {...{ theme: 'badge pill contrast' }}>
<span>{profession}</span>
<Button
aria-label={`Clear filter: ${profession}`}
data-profession={profession}
theme="contrast tertiary-inline"
title={`Clear filter: ${profession}`}
style={{ marginInlineStart: 'var(--lumo-space-xs)' }}
onClick={onClick}
>
<Icon icon="vaadin:close-small" />
</Button>
</span>
))}
</HorizontalLayout>
</VerticalLayout>
);
Counter
Badges can be used as counters, for example to show the number of unread/new messages, selection count, etc.
new tab
<Tabs>
<Tab>
<span>Inbox</span>
<span
{...{ theme: 'badge contrast pill small' }}
style={badgeStyle}
aria-label="12 unread messages"
title="12 unread messages"
>
12
</span>
</Tab>
<Tab>
<span>Important</span>
<span
{...{ theme: 'badge contrast pill small' }}
style={badgeStyle}
aria-label="3 unread messages"
title="3 unread messages"
>
3
</span>
</Tab>
<Tab>
<span>Spam</span>
<span
{...{ theme: 'badge contrast pill small' }}
style={badgeStyle}
aria-label="45 unread messages"
title="45 unread messages"
>
45
</span>
</Tab>
<Tab>
<span>Archive</span>
<span
{...{ theme: 'badge contrast pill small' }}
style={badgeStyle}
aria-label="23 unread messages"
title="23 unread messages"
>
23
</span>
</Tab>
</Tabs>
Assistive technologies, such as screen readers, interpret badges solely based on their content.
Without proper context, they may end up confusing the user.
To provide context for people using screen readers, set the badge’s aria-label
attribute.
Best Practices
Badge vs Button
Badges and Buttons are similar in appearance. This might lead users to think that badges are interactive.
Placement, language, shape, and color can all help mitigate any confusion.
First, badges shouldn’t be labeled with active verbs.
They aren’t actions, but rather static text/content.
Second, avoid placing badges directly next to Buttons, in particular if they are using similar themes.
The pill
theme variant may aid in making badges and Buttons more distinct from one another.