Badge
Compare all five semantic variants in soft, solid and outline styles, with an optional status icon.

use blinc_cn as cn;
use blinc_layout::prelude::*;
pub fn badge_demo() -> Div {
let mut samples = div().class("demo-wide").class("demo-badges");
for (label, style) in [
("Soft", cn::BadgeStyle::Soft),
("Solid", cn::BadgeStyle::Solid),
("Outline", cn::BadgeStyle::Outline),
] {
let mut row = div().class("demo-row").class("demo-badge-row");
for (name, variant) in [
("In review", cn::BadgeVariant::Default),
("Draft", cn::BadgeVariant::Secondary),
("Shipped", cn::BadgeVariant::Success),
("Pending", cn::BadgeVariant::Warning),
("Blocked", cn::BadgeVariant::Destructive),
] {
let mut badge = cn::badge(name).variant(variant).style(style);
if name == "Shipped" {
badge =
badge.icon(svg(blinc_icons::to_svg_with_stroke(blinc_icons::icons::CHECK, 12.0, 2.0)).square(12.0));
}
row = row.child(badge);
}
samples = samples.child(
div()
.class("demo-badge-group")
.child(text(label).class("demo-caption"))
.child(row),
);
}
samples
}
@layer components {
.cn-badge {
font-family: var(--font-sans);
}
.cn-badge {
border-radius: var(--radius-full);
font-size: var(--text-xs);
padding: var(--space-0-5) var(--space-2-5);
}
.cn-badge--soft-default {
background: var(--accent-subtle);
border: 1px solid var(--primary);
color: var(--primary);
}
.cn-badge--soft-secondary {
background: var(--surface-elevated);
border: 1px solid var(--border);
color: var(--text-secondary);
}
.cn-badge--soft-success {
background: var(--success-bg);
border: 1px solid var(--success);
color: var(--success);
}
.cn-badge--soft-warning {
background: var(--warning-bg);
border: 1px solid var(--warning);
color: var(--warning);
}
.cn-badge--soft-destructive {
background: var(--error-bg);
border: 1px solid var(--error);
color: var(--error);
}
.cn-badge--solid-default {
background: var(--primary);
color: var(--text-inverse);
}
.cn-badge--solid-secondary {
background: var(--secondary);
color: var(--text-inverse);
}
.cn-badge--solid-success {
background: var(--success);
color: var(--text-inverse);
}
.cn-badge--solid-warning {
background: var(--warning);
color: var(--text-inverse);
}
.cn-badge--solid-destructive {
background: var(--error);
color: var(--text-inverse);
}
.cn-badge--outline-default {
background: transparent;
border: 1px solid var(--primary);
color: var(--primary);
}
.cn-badge--outline-secondary {
background: transparent;
border: 1px solid var(--border);
color: var(--text-primary);
}
.cn-badge--outline-success {
background: transparent;
border: 1px solid var(--success);
color: var(--success);
}
.cn-badge--outline-warning {
background: transparent;
border: 1px solid var(--warning);
color: var(--warning);
}
.cn-badge--outline-destructive {
background: transparent;
border: 1px solid var(--error);
color: var(--error);
}
.cn-badge--soft-default :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--outline-default :is(path, circle, rect, ellipse, line, polygon, polyline, g) {
stroke: var(--primary);
}
.cn-badge--soft-secondary :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--outline-secondary :is(path, circle, rect, ellipse, line, polygon, polyline, g) {
stroke: var(--text-secondary);
}
.cn-badge--soft-success :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--outline-success :is(path, circle, rect, ellipse, line, polygon, polyline, g) {
stroke: var(--success);
}
.cn-badge--soft-warning :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--outline-warning :is(path, circle, rect, ellipse, line, polygon, polyline, g) {
stroke: var(--warning);
}
.cn-badge--soft-destructive :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--outline-destructive :is(path, circle, rect, ellipse, line, polygon, polyline, g) {
stroke: var(--error);
}
.cn-badge--solid-default :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--solid-secondary :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--solid-success :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--solid-warning :is(path, circle, rect, ellipse, line, polygon, polyline, g),
.cn-badge--solid-destructive :is(path, circle, rect, ellipse, line, polygon, polyline, g) {
stroke: var(--text-inverse);
}
}
Usage and properties
Present a compact status, category or count. Apply CSS after the component layer to restyle the documented parts.
Use the installation guide to add blinc_cn and its component stylesheet. Create the fixture bindings once, and return the demo from your UI builder. Values marked Bound accept Signal/Computed sources where the API supports them; structural options configure the component at construction.
| Property | Type | Update model | This example |
|---|---|---|---|
label | string | Construction | Status labels |
variant | BadgeVariant | Construction | Default, Secondary, Outline and Destructive |
Keyboard and interaction
Informational content; no activation or Tab stop is required.
Customizing it
Add application CSS after the default component layer. These selectors are the restyling surface for this component:
.cn-badge.cn-badge--soft-success.cn-badge--outline-warning
Theme and component variables: --variant.
Built-in themes
The Live theme control installs Blinc's own theme bundles, including their colours, focus rings, corner shapes and motion tokens.
pub fn theme_bundle_for(name: &str) -> blinc_theme::ThemeBundle {
match name {
"restrained" => blinc_theme::RestrainedTheme::bundle(),
"expressive" => blinc_theme::ExpressiveTheme::bundle(),
_ => blinc_theme::HybridTheme::bundle(),
}
.with_css(blinc_cn::cn_styles::CN_STYLES)
}Download the default widget and component stylesheets. Sample assets and licenses are available in the asset guide.
Documentation
From the canonical component guide.
A badge has a semantic variant and a visual treatment:
div().flex_row().gap(2.0)
.child(badge("New"))
.child(badge("3").variant(BadgeVariant::Secondary))
.child(badge("Error").variant(BadgeVariant::Destructive))
.child(badge("Beta").style(BadgeStyle::Outline))
Variants are Default, Secondary, Success, Warning and Destructive.
Styles are Soft (the default), Solid and Outline:
badge("Done").variant(BadgeVariant::Success).style(BadgeStyle::Solid)
With an Icon
.icon(..) accepts an element builder:
badge("Verified")
.variant(BadgeVariant::Success)
.icon_position(IconPosition::Start)
.icon(icon(icons::CHECK).size_px(12.0))
A Bound Label
Convert a Signal or Computed with IntoReactive:
use blinc::core::reactive::computed;
use blinc::layout::binding::IntoReactive;
let count = ctx.use_signal(3usize);
let shown = computed(move |graph| format!("{} new", graph.get(count).unwrap_or(0)));
badge("").reactive_label(shown.into_reactive())
The root is .cn-badge. Its fill, border and text colour come from
.cn-badge--{style}-{variant}, such as .cn-badge--soft-success.
A custom class supports application overrides:
badge("Done").variant(BadgeVariant::Success).class("my-badge")
.my-badge { border-radius: 4px; }
.cn-badge--soft-success { background: #052e16; border-color: #16a34a; color: #4ade80; }
Platforms and version
The component API is available in Blinc 0.6.0. The Live example runs in a dedicated worker and requires a compatible GPU surface. Preview and Code remain available when Live cannot start. The canvas has a descriptive label; a full screen-reader DOM mirror is not provided. The gallery integration is based on revision e2e55c24e078.
Recordings and live demos use the default Hybrid theme with bundled Noto Sans. The recording uses a 560 × 360 logical viewport at twice that resolution. Live follows its container and actual display density. Source base revision · Exact build source · Artifact versions and checksums · Font license.