Compact inline label for status indicators, tags, version numbers, and counts.
Provides 6 semantic variants following the shadcn/ui Badge anatomy. Badges
are purely presentational — they are <div> elements, not <button> or
<a>. For clickable or dismissible badges, compose a badge with a button.
Variants
| Variant | Visual | Typical use cases |
|---|---|---|
:default | Solid primary background | Active state, current plan, primary label |
:secondary | Muted secondary background | Neutral tag, informational, version number |
:destructive | Red/destructive background | Error, overdue, critical, danger |
:outline | Border only, transparent background | Draft, subtle metadata, low-emphasis tag |
:ghost | Transparent, accent on hover | Inline tags, chip lists with hover effect |
:link | Primary colour with underline on hover | Clickable tag acting as a link |
Basic usage
<.badge>New</.badge>
<.badge variant={:secondary}>Beta</.badge>
<.badge variant={:destructive}>Overdue</.badge>
<.badge variant={:outline}>Draft</.badge>Status indicators
Use badges to show record status in tables and cards:
<.badge variant={status_variant(@order.status)}>
{String.capitalize(@order.status)}
</.badge>Where status_variant/1 maps domain values to badge variants:
defp status_variant("active"), do: :default
defp status_variant("draft"), do: :outline
defp status_variant("overdue"), do: :destructive
defp status_variant(_other), do: :secondaryTrend indicators in stat cards
The StatCard component uses badges internally for trend labels. You can
compose the same pattern directly:
<div class="flex items-center gap-2">
<span class="text-2xl font-bold">$42,800</span>
<.badge variant={:default} class="gap-1">
<.icon name="trending-up" size={:xs} />
+12.5%
</.badge>
</div>Count / notification badge
Overlay a count badge on an icon:
<div class="relative inline-flex">
<.icon name="bell" size={:md} />
<.badge class="absolute -top-1 -right-1 h-4 w-4 p-0 flex items-center justify-center text-[10px]">
{min(@unread_count, 99)}
</.badge>
</div>Plan or tier labels
<.badge variant={:outline} class="uppercase tracking-wide text-[10px]">
Pro
</.badge>Tag list
<div class="flex flex-wrap gap-1">
<%= for tag <- @post.tags do %>
<.badge variant={:secondary}>{tag}</.badge>
<% end %>
</div>Combining with a close button (dismissible tag)
<%= for skill <- @skills do %>
<div class="inline-flex items-center gap-1">
<.badge variant={:secondary}>{skill}</.badge>
<button
phx-click="remove_skill"
phx-value-skill={skill}
class="ml-0.5 rounded-full p-0.5 hover:bg-muted"
aria-label={"Remove #{skill}"}
>
<.icon name="x" size={:xs} />
</button>
</div>
<% end %>
Summary
Functions
Renders an inline <div> styled as a badge.
Functions
Renders an inline <div> styled as a badge.
Badges are display-only elements — they have no interactive behaviour by
default. To make a badge interactive, wrap it in a <button> or <a> or
compose it with a close/remove button beside it.
The :default variant uses the primary brand colour for high-visibility
labels. :outline and :ghost are appropriate for lower-emphasis metadata.
:destructive should be reserved for genuine error or danger states.
Example
<.badge variant={:destructive}>
<.icon name="alert-triangle" size={:xs} />
Critical
</.badge>Attributes
variant(:atom) - Visual style variant. Controls background, text colour, and hover state. Default::default(solid primary). Defaults to:default. Must be one of:default,:secondary,:destructive,:outline,:ghost, or:link.class(:string) - Additional CSS classes merged viacn/1. Useuppercase tracking-widefor label-style badges, orgap-1to add an icon. Defaults tonil.- Global attributes are accepted. HTML attributes forwarded to the root
<div>element (e.g.data-testid,aria-label).
Slots
inner_block(required) - Badge content. Typically a short text label (1–3 words), count, or an icon + text combination.