# Status Pill

> Tinted status label with a leading dot, in five tones.

- **Slug:** `status-pill`
- **Kind:** atom · **Category:** Feedback
- **Source:** ported from [Beautiful UI](https://github.com/slev12397/beautiful-ui/blob/main/components/atoms/StatusPill.tsx) (MIT)
- **Docs page:** https://viewership.ai/ui/components/status-pill
- **All files in one bundle:** https://viewership.ai/ui/components/status-pill.bundle.txt
- **Structured JSON:** https://viewership.ai/ui/components/status-pill.json

## Install

1. Import the foundation tokens once (download: https://viewership.ai/ui/raw/foundation.css.txt):

```astro
---
// src/layouts/Layout.astro
import "../styles/foundation.css";
---
```

2. Copy this file into `src/components/viewership/status-pill/`:

   - `StatusPill.astro` (raw: https://viewership.ai/ui/raw/status-pill/StatusPill.astro.txt)

npm packages: none.

## Usage

```astro
---
import StatusPill from "../components/viewership/status-pill/StatusPill.astro";
---

<StatusPill />
```

## Example

The gallery demo, verbatim. Use the import path from Usage instead of `./`.

```astro
---
import StatusPill from "./StatusPill.astro";

interface Props {
  variant?: string;
}
const { variant = "Campaigns" } = Astro.props;

const batches = [
  { id: "#214", lot: "Spring Search", status: "Live", tone: "green" },
  { id: "#215", lot: "Trail Test video", status: "In review", tone: "accent" },
  { id: "#216", lot: "Gear Guide email", status: "Needs approval", tone: "orange" },
  { id: "#217", lot: "Reddit AMA post", status: "Rejected", tone: "red" },
  { id: "#218", lot: "Summer promo", status: "Queued", tone: "neutral" },
] as const;
---

{variant === "Campaigns" && (
  <ul class="list" aria-label="This week's campaigns">
    {batches.map((b) => (
      <li class="item">
        <span class="id">{b.id}</span>
        <span class="lot">{b.lot}</span>
        <StatusPill tone={b.tone}>{b.status}</StatusPill>
      </li>
    ))}
  </ul>
)}

{variant === "Without dot" && (
  <div class="row">
    <StatusPill tone="green" dot={false}>Published</StatusPill>
    <StatusPill tone="accent" dot={false}>Client</StatusPill>
    <StatusPill tone="orange" dot={false}>Low budget</StatusPill>
    <StatusPill tone="red" dot={false}>Overdue</StatusPill>
    <StatusPill dot={false}>Draft</StatusPill>
  </div>
)}

<style>
  .list {
    max-width: 380px;
    margin: 0 auto;
    padding: 4px 16px;
    list-style: none;
    border-radius: var(--vs-radius-card);
    background: var(--vs-surface);
    box-shadow: var(--vs-shadow-card);
  }
  .item {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    font-size: 14px;
  }
  .item + .item {
    border-top: 1px solid var(--vs-line);
  }
  .id {
    width: 36px;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    color: var(--vs-ink-3);
  }
  .lot {
    flex: 1;
    min-width: 0;
    color: var(--vs-ink);
  }
  .row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
  }
</style>
```

## Variants

Demo variants: `Campaigns`, `Without dot`.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `tone` | `"green" \| "orange" \| "red" \| "accent" \| "neutral"` | `"neutral"` | Color. Maps to .vs-status-pill--<tone>. |
| `dot` | `boolean` | `true` | Show the leading dot. |

## Source

### `src/components/viewership/status-pill/StatusPill.astro`

```astro
---
/**
 * StatusPill: a tinted state label with a leading dot.
 *
 * Ported from Beautiful UI `components/atoms/StatusPill.tsx`
 * (MIT, © 2026 Shane Levine). Tones are modifier classes
 * (`.vs-status-pill--green`). The dot is decorative, so the text must carry
 * the state on its own.
 *
 * @example
 * <StatusPill tone="green">Published</StatusPill>
 */
import type { HTMLAttributes } from "astro/types";

type Tone = "green" | "orange" | "red" | "accent" | "neutral";

type Props = HTMLAttributes<"span"> & {
  tone?: Tone;
  /** Show the leading dot. */
  dot?: boolean;
};

const { tone = "neutral", dot = true, class: className, ...rest } = Astro.props;
---

<span class:list={["vs-status-pill", `vs-status-pill--${tone}`, className]} {...rest}>
  {dot && <span class="vs-status-pill__dot" aria-hidden="true"></span>}
  <slot />
</span>

<style>
  .vs-status-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 24px;
    padding: 0 10px;
    border-radius: var(--vs-radius-pill);
    font-size: 13px;
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
  }
  .vs-status-pill__dot {
    width: 6px;
    height: 6px;
    flex-shrink: 0;
    border-radius: var(--vs-radius-pill);
    background: currentColor;
  }

  .vs-status-pill--green {
    background: var(--vs-green-tint);
    color: var(--vs-green);
  }
  .vs-status-pill--orange {
    background: var(--vs-orange-tint);
    color: var(--vs-orange);
  }
  .vs-status-pill--red {
    background: var(--vs-red-tint);
    color: var(--vs-red);
  }
  .vs-status-pill--accent {
    background: var(--vs-accent-tint);
    color: var(--vs-accent-ink);
  }
  .vs-status-pill--accent .vs-status-pill__dot {
    background: var(--vs-accent);
  }
  .vs-status-pill--neutral {
    background: var(--vs-inset);
    color: var(--vs-ink-2);
  }
  .vs-status-pill--neutral .vs-status-pill__dot {
    background: var(--vs-ink-3);
  }

  @media (forced-colors: active) {
    .vs-status-pill {
      outline: 1px solid CanvasText;
    }
    .vs-status-pill__dot {
      background: CanvasText;
    }
  }
</style>
```
