A versatile badge component for displaying status, categories, or small pieces of information. Supports an optional label section, multiple feedback states, and can be styled with different emphasis levels for various use cases.
The emphasis prop controls the visual style of the badge. primary uses a solid accent surface with high-contrast text; secondary (default) uses a feedback-tinted soft surface; tertiary uses a neutral surface with bold feedback-colored text; adaptive inherits ambient text color and tints from the surrounding context.
---
import Badge from "../Badge.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge emphasis="primary">Primary</Badge>
<Badge emphasis="secondary">Secondary</Badge>
<Badge emphasis="tertiary">Tertiary</Badge>
<Badge emphasis="adaptive">Adaptive</Badge>
</div>Badges support semantic feedback colors for communicating status at a glance.
---
import Badge from "../Badge.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div class={stack({ gap: "md", direction: "column" })}>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary" emphasis="primary">Primary</Badge>
<Badge feedback="success" emphasis="primary">Success</Badge>
<Badge feedback="warning" emphasis="primary">Warning</Badge>
<Badge feedback="danger" emphasis="primary">Danger</Badge>
<Badge feedback="neutral" emphasis="primary">Neutral</Badge>
</div>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary">Primary</Badge>
<Badge feedback="success">Success</Badge>
<Badge feedback="warning">Warning</Badge>
<Badge feedback="danger">Danger</Badge>
<Badge feedback="neutral">Neutral</Badge>
</div>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary" emphasis="tertiary">Primary</Badge>
<Badge feedback="success" emphasis="tertiary">Success</Badge>
<Badge feedback="warning" emphasis="tertiary">Warning</Badge>
<Badge feedback="danger" emphasis="tertiary">Danger</Badge>
<Badge feedback="neutral" emphasis="tertiary">Neutral</Badge>
</div>
</div>Four size variants are available to fit different layout contexts.
---
import Badge from "../Badge.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge size="sm">Small</Badge>
<Badge size="md">Medium</Badge>
</div>Badge inherits panel’s full surface model. background, border, and translucent work across every emphasis × feedback combination — panel’s compound variants remap each surface.* value to the correct ramp (accent under primary, palette-tinted under secondary, neutral under tertiary).
---
import Badge from "../Badge.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div class={stack({ gap: "md", direction: "column" })}>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary" emphasis="primary" background="surface.soft">
soft
</Badge>
<Badge feedback="primary" emphasis="primary" background="surface.step.1">
step.1
</Badge>
<Badge feedback="primary" emphasis="primary" background="surface.step.2">
step.2
</Badge>
<Badge feedback="primary" emphasis="primary" background="surface.step.3">
step.3
</Badge>
<Badge feedback="primary" emphasis="primary" background="surface.deep">
deep
</Badge>
<Badge feedback="primary" emphasis="primary" background="transparent">
transparent
</Badge>
</div>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary" emphasis="secondary" background="surface.soft">
soft
</Badge>
<Badge feedback="primary" emphasis="secondary" background="surface.step.1">
step.1
</Badge>
<Badge feedback="primary" emphasis="secondary" background="surface.step.2">
step.2
</Badge>
<Badge feedback="primary" emphasis="secondary" background="surface.step.3">
step.3
</Badge>
<Badge feedback="primary" emphasis="secondary" background="surface.deep">
deep
</Badge>
<Badge feedback="primary" emphasis="secondary" background="transparent">
transparent
</Badge>
</div>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary" emphasis="tertiary" background="surface.soft">
soft
</Badge>
<Badge feedback="primary" emphasis="tertiary" background="surface.step.1">
step.1
</Badge>
<Badge feedback="primary" emphasis="tertiary" background="surface.step.2">
step.2
</Badge>
<Badge feedback="primary" emphasis="tertiary" background="surface.step.3">
step.3
</Badge>
<Badge feedback="primary" emphasis="tertiary" background="surface.deep">
deep
</Badge>
<Badge feedback="primary" emphasis="tertiary" background="transparent">
transparent
</Badge>
</div>
</div>Embed icons inside the badge content slot to reinforce meaning alongside the status label. Use 1em for icon sizes so they scale naturally with the badge’s size prop. The label prop (or slot="label" in Astro) adds a secondary section on the left — useful for pairing a version number or category with an icon-annotated value on the right.
---
import Badge from "../Badge.astro";
import { Icon } from "astro-icon/components";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";
---
<div class={stack({ gap: "xl", direction: "column" })}>
<!-- Solid badges with status icons -->
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="success">
<Icon name="lucide:circle-check" class={css({ w: "1em", h: "1em" })} />
Deployed
</Badge>
<Badge feedback="warning">
<Icon name="lucide:triangle-alert" class={css({ w: "1em", h: "1em" })} />
Pending
</Badge>
<Badge feedback="danger">
<Icon name="lucide:circle-x" class={css({ w: "1em", h: "1em" })} />
Failed
</Badge>
<Badge feedback="primary">
<Icon name="lucide:info" class={css({ w: "1em", h: "1em" })} />
Info
</Badge>
</div>
<!-- Outlined badges with icons -->
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="success" emphasis="secondary">
<Icon name="lucide:circle-check" class={css({ w: "1em", h: "1em" })} />
Active
</Badge>
<Badge feedback="warning" emphasis="secondary">
<Icon name="lucide:triangle-alert" class={css({ w: "1em", h: "1em" })} />
Review
</Badge>
<Badge feedback="danger" emphasis="secondary">
<Icon name="lucide:circle-x" class={css({ w: "1em", h: "1em" })} />
Blocked
</Badge>
<Badge feedback="neutral" emphasis="secondary">
<Icon name="lucide:lock" class={css({ w: "1em", h: "1em" })} />
Private
</Badge>
</div>
<!-- Named label slot with icon in content -->
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary" emphasis="primary">
<Fragment slot="label">v2.1</Fragment>
<Icon name="lucide:star" class={css({ w: "1em", h: "1em" })} />
Featured
</Badge>
<Badge feedback="success" emphasis="primary">
<Fragment slot="label">Prod</Fragment>
<Icon name="lucide:circle-check" class={css({ w: "1em", h: "1em" })} />
Live
</Badge>
<Badge feedback="neutral" emphasis="secondary">
<Fragment slot="label">Auth</Fragment>
<Icon name="lucide:lock" class={css({ w: "1em", h: "1em" })} />
Required
</Badge>
</div>
</div>Buttons placed inside a badge — in either the content or label slot — are automatically resized to fit the badge’s dimensions. You don’t need to set a size prop on the button; it scales proportionally with the badge’s own size variant. Use shape="circle" emphasis="ghost" for a compact dismiss target that inherits the badge’s color context without adding visual noise.
To opt out of this behavior, set buttonFit={false} on the badge — buttons will then render at their own default size.
---
import Badge from "../Badge.astro";
import Button from "@pindoba/astro-button";
import { Icon } from "astro-icon/components";
import { stack } from "@pindoba/styled-system/patterns";
---
<div class={stack({ gap: "xl", direction: "column" })}>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge size="sm" feedback="neutral" emphasis="secondary">
sm badge
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button>
</Badge>
<Badge size="md" feedback="neutral" emphasis="secondary">
md badge
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button>
</Badge>
</div>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary">
New feature
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button>
</Badge>
<Badge feedback="success">
Deployed
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button>
</Badge>
<Badge feedback="warning">
Pending
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button>
</Badge>
<Badge feedback="danger">
Failed
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button>
</Badge>
<Badge feedback="neutral">
Archived
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button>
</Badge>
</div>
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<Badge feedback="primary" emphasis="secondary">
<Fragment slot="label">
React
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button
>
</Fragment>
18 issues
</Badge>
<Badge feedback="neutral" emphasis="secondary">
<Fragment slot="label">
Filter
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button
>
</Fragment>
12 results
</Badge>
<Badge feedback="success">
<Fragment slot="label">
v2.1
<Button shape="circle" emphasis="ghost"><Icon name="lucide:x" /></Button
>
</Fragment>
Released
</Badge>
</div>
</div>The label prop (Svelte) or label slot (Astro) adds a secondary section to the badge. Use passThrough to apply custom Panda CSS styles or HTML attributes to any slot.
---
import Badge from "../Badge.astro";
import { stack } from "@pindoba/styled-system/patterns";
---
<div
class={stack({
gap: "md",
direction: "row",
align: "center",
flexWrap: "wrap",
})}
>
<!-- With label slot -->
<Badge feedback="success">
<Fragment slot="label">New</Fragment>
Feature
</Badge>
<!-- Label as primary emphasis -->
<Badge feedback="primary" emphasis="primary">
<Fragment slot="label">v2.0</Fragment>
Release
</Badge>
<!-- Secondary with label -->
<Badge feedback="warning" emphasis="secondary">
<Fragment slot="label">Beta</Fragment>
Preview
</Badge>
<!-- PassThrough custom styles -->
<Badge
feedback="danger"
passThrough={{ root: { style: { letterSpacing: "wider" } } }}
>
Custom
</Badge>
<!-- PassThrough with ARIA props -->
<Badge
feedback="success"
passThrough={{
root: { props: { role: "status", "aria-label": "Success status" } },
}}
>
Accessible
</Badge>
</div>| prop | type | default | req | description |
|---|---|---|---|---|
| feedback | "primary""success""warning""danger""neutral" | "primary" | Semantic feedback color scheme. primary: primary color palette. success: green. warning: orange. danger: red. neutral: gray. | |
| emphasis | "primary""secondary""tertiary""adaptive" | "secondary" | Visual emphasis level. primary: solid accent surface with high-contrast text. secondary: feedback-tinted soft surface. tertiary: neutral surface with bold feedback text. adaptive: inherit ambient text…
Visual emphasis level. primary: solid accent surface with high-contrast text. secondary: feedback-tinted soft surface. tertiary: neutral surface with bold feedback text. adaptive: inherit ambient text and tint. Type Default Required | |
| size | "xs""sm""md""lg" | "md" | Size variant for the badge. xs: extra small. sm: small. md: default. lg: large. | |
| background | "surface.soft""surface.step.1""surface.step.2""surface.step.3""surface.deep""transparent" | "surface.soft" (or "transparent" when emphasis="adaptive") | Surface fill. Forwarded to panel and remapped per emphasis (accent ramp under primary, palette-tinted under secondary, neutral under tertiary). transparent for no fill. | |
| border | "none""default""bold""muted""accent" | "accent" | "default" | "muted" | Border ring strength. Forwarded to panel. Defaults to "accent" for primary, "default" for adaptive, "muted" otherwise. | |
| translucent | boolean | false | Applies a frosted-glass backdrop blur to the surface. | |
| buttonFit | boolean | true | When true (default), buttons placed inside the badge content or label slot are automatically resized to fit the badge's dimensions. Set to false to let buttons render at their own default size. | |
| label | stringSnippetslot | undefined | Optional label displayed as a separate section within the badge. In Svelte, accepts a string or Snippet; in Astro, use slot="label". | |
| passThrough | { root?: { style?: SystemStyleObject; props?: HTMLAttributes<HTMLSpanElement> }; label?: { style?: SystemStyleObject; props?: HTMLAttributes<HTMLDivElement> }; content?: { style?: SystemStyleObject; props?: HTMLAttributes<HTMLDivElement> } } | undefined | Custom styling and props for badge slots. Each slot accepts style (SystemStyleObject) and props (HTML attributes). | |
| children | Snippetslot | undefined | Badge content rendered inside the content slot. | |
| ...rest | HTMLAttributes<HTMLSpanElement> | - | Standard HTML span attributes. |