Badge
A badge shows a count or a status on another element: unread messages on an icon, a new item in a navigation bar. A large badge holds up to four characters; a small one is a 6dp dot for news without a number. See the M3 badges guidelines.
Usage
import { createBadge } from 'mtrl';
const badge = createBadge({ label: 3 });
document.body.append(badge.element);
<m-badge label="3"></m-badge>
import { Badge } from 'mtrl/react';
export function Example() {
return (
<Badge label="3" />
);
}
<script setup lang="ts">
import { MBadge } from 'mtrl/vue';
</script>
<template>
<MBadge label="3" />
</template>
<script lang="ts">
import { Badge } from 'mtrl/svelte';
</script>
<Badge label="3" />
import { Badge } from 'mtrl/solid';
export function Example() {
return (
<Badge label="3" />
);
}
The factory's target wraps an element and puts the badge on its corner, set by position.
The web component is the badge alone, placed where it is written. Navigation items and tabs
take a badge of their own, through their badge option.
Examples
A maximum
Above max, a number shows as {max}+. A label longer than four characters is shortened:
12500 to 999+, text to its first four characters.
import { createBadge } from 'mtrl';
const badge = createBadge({ label: 1200, max: 999, color: 'primary' });
document.body.append(badge.element);
<m-badge label="1200" max="999" color="primary"></m-badge>
import { Badge } from 'mtrl/react';
export function Example() {
return (
<Badge label="1200" max={999} color="primary" />
);
}
<script setup lang="ts">
import { MBadge } from 'mtrl/vue';
</script>
<template>
<MBadge label="1200" :max="999" color="primary" />
</template>
<script lang="ts">
import { Badge } from 'mtrl/svelte';
</script>
<Badge label="1200" max={999} color="primary" />
import { Badge } from 'mtrl/solid';
export function Example() {
return (
<Badge label="1200" max={999} color="primary" />
);
}
Hidden at zero
An empty label or 0 hides the badge, and any other label shows it again.
import { createBadge } from 'mtrl';
const badge = createBadge({ label: 5 });
document.body.append(badge.element);
function markAllRead() {
badge.setLabel(0);
}
<m-badge label="5"></m-badge>
<script type="module">
const badge = document.querySelector('m-badge');
function markAllRead() {
badge.setAttribute('label', "0");
}
</script>
import { useState } from 'react';
import { Badge } from 'mtrl/react';
export function Example() {
const [label, setLabel] = useState(5);
const markAllRead = () => setLabel(0);
return (
<Badge label={label} />
);
}
<script setup lang="ts">
import { ref } from 'vue';
import { MBadge } from 'mtrl/vue';
const label = ref(5);
function markAllRead() {
label.value = 0;
}
</script>
<template>
<MBadge :label="label" />
</template>
<script lang="ts">
import { Badge } from 'mtrl/svelte';
let label = $state(5);
function markAllRead() {
label = 0;
}
</script>
<Badge label={label} />
import { createSignal } from 'solid-js';
import { Badge } from 'mtrl/solid';
export function Example() {
const [label, setLabel] = createSignal(5);
const markAllRead = () => setLabel(0);
return (
<Badge label={label()} />
);
}
API
Options
| Option | Type | Default | Description |
|---|---|---|---|
label |
string | number |
'' |
What a large badge shows |
variant |
'small' | 'large' |
'large' |
A dot, or a badge with a label |
max |
number |
undefined |
Above it, a number shows as {max}+ |
color |
'error' | 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'info' |
'error' |
Its color role |
target |
HTMLElement |
undefined |
The element it is attached to, which it wraps; it needs a parent |
position |
'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' |
'top-right' |
Which corner of the target |
visible |
boolean |
true |
Whether it starts shown |
class |
string |
undefined |
Additional CSS classes |
prefix |
string |
'mtrl' |
Prefix for CSS class names |
The web component takes label (or its text), variant, color and max as attributes, and
visible as a property.
Methods
| Method | Parameters | Returns | Description |
|---|---|---|---|
setLabel(label) / getLabel() |
label: string | number |
BadgeComponent / string |
The label, as shown; setting it hides the badge when it is empty or 0, and shows it otherwise |
setContent(content) / getContent() |
content: string | number |
BadgeComponent / string |
The same as setLabel() and getLabel() |
setMax(max) |
max: number |
BadgeComponent |
The maximum, applied to the label |
show() / hide() / toggle(visible?) |
visible?: boolean |
BadgeComponent |
Shows or hides it |
isVisible() |
none | boolean |
Whether it is shown |
setVariant(variant) / setColor(color) / setPosition(position) |
string |
BadgeComponent |
The variant, the color, the corner |
attachTo(target) / detach() |
target: HTMLElement |
BadgeComponent |
Wraps a target and moves the badge onto it; detached, it moves to the end of document.body |
addClass(...classes) / removeClass(...classes) |
...classes: string[] |
BadgeComponent |
CSS classes |
destroy() |
none | void |
Removes it, and unwraps its target |
| Property | Type | Description |
|---|---|---|
element |
HTMLElement |
The badge |
wrapper |
HTMLElement | undefined |
The element wrapping the target and the badge |
A badge has no events: it has on() and off(), and emits nothing.
Accessibility
- A large badge has
role="status", so a change of its label is announced. - A small badge is
aria-hidden: name the element it is on with what it says, such as "Inbox, new messages". - A badge is not focusable; the element it is on takes the interaction.
Styling
.mtrl-badge, .mtrl-badge--small, .mtrl-badge--large { }
.mtrl-badge--error, .mtrl-badge--primary, .mtrl-badge--secondary, .mtrl-badge--tertiary { }
.mtrl-badge--success, .mtrl-badge--warning, .mtrl-badge--info { }
.mtrl-badge--positioned { } /* on a target */
.mtrl-badge--top-right, .mtrl-badge--top-left, .mtrl-badge--bottom-right, .mtrl-badge--bottom-left { }
.mtrl-badge--invisible, .mtrl-badge--overflow { }
.mtrl-badge__wrapper { } /* the target's wrapper */
Measurements
| Attribute | Value |
|---|---|
| Small | 6dp dot, 3dp beyond the target's corner |
| Large | 16dp high, at least 16dp wide, 8dp corners, 4dp padding, 8dp beyond the target's corner |
| Large, with a maximum | 34dp wide at most |
| Colors | The role and its on- pair: error and on-error by default |