Badge
Use CBadge for short inline status, category, count, or metadata text. Badge is a visual label, not a Button, selectable Chip, removable Tag, or live announcement region.
Badge at a glance
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BadgeAtAGlance(Component):
template = """
<section class="badge-glance" aria-labelledby="badge-glance-title">
<div>
<p>Mineral archive ยท specimen 184</p>
<h2 id="badge-glance-title">Azurite rosette</h2>
</div>
<c-CGroup>
<c-CBadge intent="primary">Copper carbonate</c-CBadge>
<c-CBadge intent="success" variant="outline">Verified</c-CBadge>
<c-CBadge shape="pill">3 fragments</c-CBadge>
</c-CGroup>
</section>
"""
css = """
:where(.badge-glance) {
display: flex;
flex-wrap: wrap;
align-items: end;
justify-content: space-between;
gap: 1rem;
max-inline-size: 38rem;
padding: 1.25rem;
border: 1px solid light-dark(#b7c6cf, #526873);
border-radius: 0.85rem;
background: light-dark(#f5fbff, #17232a);
color: CanvasText;
font-family: ui-sans-serif, system-ui, sans-serif;
}
:where(.badge-glance h2, .badge-glance p) {
margin: 0;
}
:where(.badge-glance p) {
color: light-dark(#496471, #a9c5d2);
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
}
:where(.badge-glance h2) {
margin-block-start: 0.25rem;
font-size: 1.1rem;
}
"""
preview = BadgeAtAGlance()
preview # noqa: B018
Compose a Badge
The default slot supplies the visible meaning. It is required.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BasicBadges(Component):
template = """
<div class="badge-basic">
<p>Fluorite <c-CBadge>New</c-CBadge></p>
<p>Cabinet 7 <c-CBadge shape="pill">24</c-CBadge></p>
<p>Catalog record <c-CBadge variant="outline">Draft</c-CBadge></p>
</div>
"""
css = """
:where(.badge-basic) {
display: grid;
gap: 0.75rem;
max-inline-size: 24rem;
color: CanvasText;
font-family: ui-sans-serif, system-ui, sans-serif;
}
:where(.badge-basic p) {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin: 0;
padding-block-end: 0.5rem;
border-block-end: 1px solid light-dark(#d8d2c6, #4f4a42);
}
"""
preview = BasicBadges()
preview # noqa: B018
<c-CBadge intent="success">Verified</c-CBadge>
Compose the same result in Python:
from citry_ui import CBadge
verified = CBadge(intent="success", slots={"default": "Verified"})
Carry meaning with text
Intent selects a palette. The visible label must still explain the state, so the result remains understandable without color.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BadgeIntents(Component):
template = """
<c-CGroup class_="badge-intents">
<c-CBadge intent="neutral">Unsorted</c-CBadge>
<c-CBadge intent="primary">In study</c-CBadge>
<c-CBadge intent="success">Verified</c-CBadge>
<c-CBadge intent="warn">Handle carefully</c-CBadge>
<c-CBadge intent="danger">Restricted</c-CBadge>
</c-CGroup>
"""
css = """
:where(.badge-intents) {
max-inline-size: 34rem;
padding: 1rem;
border-radius: 0.75rem;
background: light-dark(#f5f1e8, #25221e);
color: CanvasText;
font-family: ui-sans-serif, system-ui, sans-serif;
}
"""
preview = BadgeIntents()
preview # noqa: B018
Choose visual emphasis
Use soft for quiet metadata, solid for stronger emphasis, and outline when the surrounding surface should remain visible.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BadgeVariants(Component):
template = """
<c-CStack class_="badge-variants" gap="sm">
<c-CGroup><strong>Soft</strong><c-CBadge intent="primary">Lapis</c-CBadge></c-CGroup>
<c-CGroup><strong>Solid</strong><c-CBadge intent="primary" variant="solid">Lapis</c-CBadge></c-CGroup>
<c-CGroup><strong>Outline</strong><c-CBadge intent="primary" variant="outline">Lapis</c-CBadge></c-CGroup>
</c-CStack>
"""
css = """
:where(.badge-variants) {
max-inline-size: 20rem;
color: CanvasText;
font-family: ui-sans-serif, system-ui, sans-serif;
}
:where(.badge-variants > [data-citry-ui-part="group"]) {
justify-content: space-between;
padding: 0.75rem;
border: 1px solid light-dark(#d4cabc, #514940);
border-radius: 0.6rem;
}
"""
preview = BadgeVariants()
preview # noqa: B018
Choose size and shape
Sizes change compact type and spacing. Shape changes only the corner radius.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BadgeSizesAndShapes(Component):
template = """
<c-CStack class_="badge-sizes">
<c-CGroup align="baseline">
<c-CBadge size="sm">Small</c-CBadge>
<c-CBadge>Medium</c-CBadge>
<c-CBadge size="lg">Large</c-CBadge>
</c-CGroup>
<c-CGroup>
<c-CBadge shape="rounded" intent="success">Rounded</c-CBadge>
<c-CBadge shape="pill" intent="success">Pill</c-CBadge>
</c-CGroup>
</c-CStack>
"""
css = """
:where(.badge-sizes) {
max-inline-size: 28rem;
padding: 1rem;
border: 1px solid light-dark(#cbd5d9, #475a62);
border-radius: 0.75rem;
color: CanvasText;
font-family: ui-sans-serif, system-ui, sans-serif;
}
"""
preview = BadgeSizesAndShapes()
preview # noqa: B018
Add registered icons
Use the start and end slots for short decorative content. Keep the default label meaningful without the icon.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BadgeIcons(Component):
template = """
<c-CGroup class_="badge-icons">
<c-CBadge intent="success">
<c-fill name="start"><c-CIcon name="check" /></c-fill>
<c-fill name="default">Verified origin</c-fill>
</c-CBadge>
<c-CBadge intent="warn" variant="outline">
<c-fill name="default">Requires gloves</c-fill>
<c-fill name="end"><c-CIcon name="triangle-alert" /></c-fill>
</c-CBadge>
</c-CGroup>
"""
css = """
:where(.badge-icons) {
max-inline-size: 30rem;
padding: 1rem;
background: light-dark(#f4f0e7, #29251f);
color: CanvasText;
font-family: ui-sans-serif, system-ui, sans-serif;
}
"""
preview = BadgeIcons()
preview # noqa: B018
Give counts context
A lone number is ambiguous. Put counts beside understandable owner text and include the count's meaning in the owner accessible name when needed.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BadgeCountsAndContext(Component):
template = """
<nav class="badge-counts" aria-label="Mineral archive queues">
<a href="#unfiled" aria-label="Unfiled specimens, 12 items">
<span>Unfiled specimens</span><c-CBadge shape="pill">12</c-CBadge>
</a>
<a href="#review" aria-label="Awaiting review, 4 items">
<span>Awaiting review</span><c-CBadge shape="pill" intent="warn">4</c-CBadge>
</a>
</nav>
"""
css = """
:where(.badge-counts) {
display: grid;
gap: 0.375rem;
max-inline-size: 22rem;
font-family: ui-sans-serif, system-ui, sans-serif;
}
:where(.badge-counts a) {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.75rem;
border-radius: 0.6rem;
color: CanvasText;
text-decoration: none;
}
:where(.badge-counts a:hover) {
background: light-dark(#ece6da, #322d27);
}
"""
preview = BadgeCountsAndContext()
preview # noqa: B018
Badge does not cap large values or hide zero. Format the slot content in your application so display and accessible context stay under one policy.
Position a Badge around an owner
Badge owns no positioning or overlap. Use ordinary CSS when a count belongs at the corner of a Button, Avatar, or other item.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BadgePositioning(Component):
template = """
<div class="badge-positioning">
<c-CButton c-attrs="{'aria-label': 'Field notes, 7 unread'}">
Field notes
<c-CBadge intent="danger" shape="pill">7</c-CBadge>
</c-CButton>
</div>
"""
css = """
:where(.badge-positioning) {
min-block-size: 7rem;
padding: 1.5rem;
color: CanvasText;
font-family: ui-sans-serif, system-ui, sans-serif;
}
:where(.badge-positioning [data-citry-ui-part="button"]) {
position: relative;
}
:where(.badge-positioning [data-citry-ui-part="badge"]) {
position: absolute;
inset-block-start: 0;
inset-inline-end: 0;
translate: 45% -45%;
}
"""
preview = BadgePositioning()
preview # noqa: B018
Customize Badge
Override public variables on an ancestor or one Badge. Stable part selectors support local geometry without relying on private classes.
Show code
import citry_ui
from citry import Component, citry
citry.register_library(citry_ui)
class BadgeCustomization(Component):
template = """
<c-CGroup class_="badge-themes">
<div class="badge-themes__quartz">
<c-CBadge>Quartz archive</c-CBadge>
</div>
<div class="badge-themes__basalt">
<c-CBadge variant="outline">Basalt archive</c-CBadge>
</div>
</c-CGroup>
"""
css = """
:where(.badge-themes > div) {
padding: 1.25rem;
border-radius: 0.75rem;
}
:where(.badge-themes__quartz) {
--cui-badge-background: #f0e7ff;
--cui-badge-foreground: #4c1d75;
--cui-badge-radius: 0.2rem;
background: #faf7ff;
}
:where(.badge-themes__basalt) {
color-scheme: dark;
--cui-badge-background: #1e2930;
--cui-badge-foreground: #d7edf2;
--cui-badge-border-color: #72a8b5;
--cui-badge-radius: 999px;
background: #10171b;
}
"""
preview = BadgeCustomization()
preview # noqa: B018
Accessibility and behavior
Badge renders a neutral, unfocusable span with no JavaScript. Do not place Buttons, links, inputs, or other controls inside it. Put Badge inside the interactive owner instead.
Changing Badge text does not create a live announcement. Use a persistent status or Alert surface when a browser update must be announced.
API reference
Inputs
CBadge server inputs
Server inputs are passed in a template through <c-CBadge ... /> or in Python through CBadge(...).
| Input | Type | Default | Effect |
|---|---|---|---|
variant | "soft" | "solid" | "outline" (CBadgeVariant) | "soft" | Selects quiet fill, strong fill, or outlined emphasis. |
intent | "neutral" | "primary" | "success" | "warn" | "danger" (CBadgeIntent) | "neutral" | Selects a visual palette; authored text must still carry status meaning. |
size | "sm" | "md" | "lg" (CBadgeSize) | "md" | Sets compact height, type, padding, icon size, and gap. |
shape | "rounded" | "pill" (CBadgeShape) | "rounded" | Selects compact rounded or fully pill-shaped geometry. |
class_ | str | Mapping[str, bool] | Sequence[CClassValue] | None (CClassValue) | None | Adds root classes and merges them with attrs. |
style | str | Mapping[str, str | int | float | bool | None] | Sequence[CStyleValue] | None (CStyleValue) | None | Adds root inline styles and merges them with attrs. |
attrs | Mapping[str, object] | None | None | Adds copied trusted native, data, and targeted Alpine root attributes without replacing Badge anatomy, semantics, or Citry runtime fields. |
Slots
Slots are passed as nested content or <c-fill> tags in a template, or through the slots={...} argument in Python.
CBadge slots
| Slot | Required | Data | Fallback |
|---|---|---|---|
default | yes | {} (CBadgeDefaultSlotData) | Missing fill raises before rendering. |
start | no | {} (CBadgeStartSlotData) | Leading wrapper omitted. |
end | no | {} (CBadgeEndSlotData) | Trailing wrapper omitted. |
Events
-
Methods
-
CSS
CSS variables to theme the components. Set them on an ancestor or the component itself.
CBadge CSS variables
Apply these variables to CBadge or one of its ancestors.
| Variable | Type | Purpose | Default |
|---|---|---|---|
--cui-badge-background | color | Root fill. | Variant- and intent-derived color. |
--cui-badge-foreground | color | Label and icon foreground. | Contrast-checked variant and intent color. |
--cui-badge-border-color | color | Root border. | Variant-derived transparent or currentColor. |
--cui-badge-radius | length | Root corner radius. | Shape-derived 0.375rem or 999px. |
--cui-badge-min-height | length | Compact minimum block size. | Size-derived length. |
--cui-badge-padding-inline | length | Root inline padding. | Size-derived length. |
--cui-badge-gap | length | Space between supplied slot wrappers. | Size-derived length. |
--cui-badge-font-size | length | Label font size. | Size-derived length. |
--cui-badge-font-weight | font-weight | Label weight. | 650 |
Attributes
HTML attributes defined on the components that you can refer to for CSS, inspection, and testing. Read-only.
CBadge attributes
| Attribute | Element | Type | Meaning |
|---|---|---|---|
data-variant | Root | "soft" | "solid" | "outline" | Reflects the selected emphasis treatment. |
data-intent | Root | "neutral" | "primary" | "success" | "warn" | "danger" | Reflects the selected visual palette. |
data-size | Root | "sm" | "md" | "lg" | Reflects compact geometry. |
data-shape | Root | "rounded" | "pill" | Reflects corner geometry. |
Selectors
Selectors for the DOM nodes in the components that you can use for CSS, inspection, and testing.
CBadge selectors
| Selector | Element | Purpose |
|---|---|---|
[data-citry-ui-part="badge"] | Native span root | Stable Badge root and attrs destination. |
[data-citry-ui-part="start"] | Optional leading wrapper | Leading icon/content layout. |
[data-citry-ui-part="label"] | Required label wrapper | Visible meaning-bearing content. |
[data-citry-ui-part="end"] | Optional trailing wrapper | Trailing icon/content layout. |
Interfaces
Aliases and data shapes referenced above.
Input type aliases
| Interface | Definition |
|---|---|
CClassValue | str | Mapping[str, bool] | Sequence[CClassValue] |
CStyleValue | str | Mapping[str, str | int | float | bool | None] | Sequence[CStyleValue] |
CBadgeVariant | Literal["soft", "solid", "outline"] |
CBadgeIntent | Literal["neutral", "primary", "success", "warn", "danger"] |
CBadgeSize | Literal["sm", "md", "lg"] |
CBadgeShape | Literal["rounded", "pill"] |
CBadgeDefaultSlotData
Empty dataclass: {}.
CBadgeStartSlotData
Empty dataclass: {}.
CBadgeEndSlotData
Empty dataclass: {}.
Translation keys
-