FairGarden Design

Badge

A short static label, a state or a count, in a 24 px pill with caps. Never a button, and never more than three words.

import { Badge } from '@fairgarden-private/design/components/Badge'

Badges keep caps: author the label in sentence case and type-label sets the caps. Every fill has an edge, so a badge keeps its shape in print, where fills drop and edges and words print black. Use one badge per item, two at most.

Outline, pill, static fill, sticker, status and count

Outline, pill, static fill, sticker, status and count

With no variant the badge is the outline form. variant="solid" is the pill: a step-9 fill with its edge and a contrast-ink label. variant="static" is the static fill: a step-4 fill of the secondary with its step-11 edge and a --primary12 label, which a solid pill on pink, red, crimson, gold, ruby or tomato takes too. variant="sticker" is a nested light face with a ring and bold caps, the same on every ground; use one per module. status draws the status glyph plus the word on the status fill. numeric sets a count in the data face.

MembersNewMembers onlyEst. 1998
GuidedOpenMuddyClosed
312128
BadgeVariants.tsx
import { Badge } from '@fairgarden-private/design/components/Badge'
import styles from './variants.module.css'

/** Labels are authored in sentence case; badges set the caps. */
export function BadgeVariants() {
  return (
    <div className={styles.stack}>
      <div className={styles.row}>
        <Badge>Members</Badge>
        <Badge variant="solid">New</Badge>
        <Badge variant="static">Members only</Badge>
        <Badge variant="sticker">Est. 1998</Badge>
      </div>
      <div className={styles.row}>
        <Badge status="info">Guided</Badge>
        <Badge status="success">Open</Badge>
        <Badge status="warning">Muddy</Badge>
        <Badge status="danger">Closed</Badge>
      </div>
      <div className={styles.row}>
        <Badge numeric>3</Badge>
        <Badge numeric>12</Badge>
        <Badge numeric>128</Badge>
      </div>
    </div>
  )
}

Primary and secondary

Primary and secondary

secondary is the pill's accent or taxonomy scale; on crimson, gold, pink, red, ruby and tomato, which carry no text on step 9, the pill takes the static fill instead. status sets secondary to its status scale (info indigo, success green, warning amber, danger red) unless you pass one. primary inks the outline, sticker and count.

Scope accentAmberIndigoOrangeRed, static fill
Primary plumBronze sticker7Status override
BadgeColor.tsx
import { Badge } from '@fairgarden-private/design/components/Badge'
import styles from './color.module.css'

/**
 * `secondary` is the pill's fill (an accent or taxonomy scale). Scales with
 * no step-9 text ink, such as red, take the static fill. `primary` inks the
 * outline, sticker and count; `status` computes its own secondary.
 */
export function BadgeColor() {
  return (
    <div className={styles.stack}>
      <div className={styles.row}>
        <Badge variant="solid">Scope accent</Badge>
        <Badge variant="solid" secondary="amber">
          Amber
        </Badge>
        <Badge variant="solid" secondary="indigo">
          Indigo
        </Badge>
        <Badge variant="solid" secondary="orange">
          Orange
        </Badge>
        <Badge variant="solid" secondary="red">
          Red, static fill
        </Badge>
      </div>
      <div className={styles.row}>
        <Badge primary="plum">Primary plum</Badge>
        <Badge variant="sticker" primary="bronze">
          Bronze sticker
        </Badge>
        <Badge numeric primary="slate">
          7
        </Badge>
        <Badge status="warning" secondary="orange">
          Status override
        </Badge>
      </div>
    </div>
  )
}

On grounds

On paper and forest

Saturated grounds take no accent fills: use the outline badge there.

paper

MembersNewEst. 1998OpenClosed4

forest

MembersNewEst. 1998OpenClosed4
BadgeGrounds.tsx
import { Badge } from '@fairgarden-private/design/components/Badge'
import { PresetGround } from '@/components/PresetGround'
import styles from './grounds.module.css'

const presets = ['paper', 'forest'] as const

/**
 * On paper the status badge takes its soft fill; on forest it takes the
 * outline form. The sticker stays a light face on both.
 */
export function BadgeGrounds() {
  return (
    <div className={styles.row}>
      {presets.map((preset) => (
        <PresetGround key={preset} preset={preset} className={styles.face}>
          <p className={styles.name}>{preset}</p>
          <div className={styles.badges}>
            <Badge>Members</Badge>
            <Badge variant="solid" secondary="amber">
              New
            </Badge>
            <Badge variant="sticker">Est. 1998</Badge>
            <Badge status="success">Open</Badge>
            <Badge status="danger">Closed</Badge>
            <Badge numeric>4</Badge>
          </div>
        </PresetGround>
      ))}
    </div>
  )
}

API Reference

Badge

A static label in caps (type-label, authored in sentence case; badges keep caps [D160]), 24 px tall, --radius-round. Use one badge per item, two at most. On saturated grounds use the outline badge: they take no accent fills. Fills drop in print; edges and words print black.

PropTypeDescription
numeric
boolean | undefined
primary
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null
| undefined

Primary Radix scale: the outline, sticker and count inks. Never defaulted; omitted, it inherits the scope [D133].

secondary
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null
| undefined

Secondary Radix scale: the solid pill’s fill (the accent or taxonomy scale). With status, the status scale replaces it unless passed.

status
BadgeStatus | undefined
statusLabel
string | undefined

The status glyph’s accessible name; defaults to the English status word.

variant
'solid' | 'static' | 'sticker' | undefined

Omitted: the outline badge (--ds-stroke-1-5 --primary12 edge and label). solid: the pill badge, a step-9 fill of the secondary with its edge and a contrast-ink label; on a scale with no step-9 text ink (pink, red, crimson, gold, ruby, tomato) it takes the static fill. static: the static fill, a --secondary4 fill with a --secondary11 edge and a --primary12 label (§10.11). sticker: a nested paper face with a ring and bold caps, the same on every ground; one per module.

StatusGlyph

PropTypeDescription
label
string | null | undefined

Accessible name, normally the status word. Omit it, or pass null, when an adjacent word already names the status: the glyph is then hidden from assistive technology.

status
Status | undefined

Additional types

badge
type badge = badge
BadgeProps

Props for Badge: span props, render, the kind (variant, status or numeric) and the color axes.

type BadgeProps =
  | (React.ClassAttributes<HTMLSpanElement> &
      React.HTMLAttributes<HTMLSpanElement> &
      __type & { variant?: 'solid' | 'static' | 'sticker'; status?: undefined; numeric?: false } & {
        primary?:
          | 'ruby'
          | 'olive'
          | 'sage'
          | 'slate'
          | 'sand'
          | 'gray'
          | 'mauve'
          | 'brown'
          | 'bronze'
          | 'gold'
          | 'red'
          | 'crimson'
          | 'tomato'
          | 'pink'
          | 'plum'
          | 'indigo'
          | 'iris'
          | 'violet'
          | 'purple'
          | null;
        secondary?:
          | 'ruby'
          | 'olive'
          | 'sage'
          | 'slate'
          | 'sand'
          | 'gray'
          | 'mauve'
          | 'brown'
          | 'bronze'
          | 'gold'
          | 'red'
          | 'crimson'
          | 'tomato'
          | 'pink'
          | 'plum'
          | 'indigo'
          | 'iris'
          | 'violet'
          | 'purple'
          | 'amber'
          | 'blue'
          | 'cyan'
          | 'grass'
          | 'green'
          | 'jade'
          | 'lime'
          | 'mint'
          | 'orange'
          | 'sky'
          | 'teal'
          | 'yellow'
          | null;
        statusLabel?: string;
      })
  | (React.ClassAttributes<HTMLSpanElement> &
      React.HTMLAttributes<HTMLSpanElement> &
      __type & { variant?: undefined; status: BadgeStatus; numeric?: false } & {
        primary?:
          | 'ruby'
          | 'olive'
          | 'sage'
          | 'slate'
          | 'sand'
          | 'gray'
          | 'mauve'
          | 'brown'
          | 'bronze'
          | 'gold'
          | 'red'
          | 'crimson'
          | 'tomato'
          | 'pink'
          | 'plum'
          | 'indigo'
          | 'iris'
          | 'violet'
          | 'purple'
          | null;
        secondary?:
          | 'ruby'
          | 'olive'
          | 'sage'
          | 'slate'
          | 'sand'
          | 'gray'
          | 'mauve'
          | 'brown'
          | 'bronze'
          | 'gold'
          | 'red'
          | 'crimson'
          | 'tomato'
          | 'pink'
          | 'plum'
          | 'indigo'
          | 'iris'
          | 'violet'
          | 'purple'
          | 'amber'
          | 'blue'
          | 'cyan'
          | 'grass'
          | 'green'
          | 'jade'
          | 'lime'
          | 'mint'
          | 'orange'
          | 'sky'
          | 'teal'
          | 'yellow'
          | null;
        statusLabel?: string;
      })
  | (React.ClassAttributes<HTMLSpanElement> &
      React.HTMLAttributes<HTMLSpanElement> &
      __type & { variant?: undefined; status?: undefined; numeric: true } & {
        primary?:
          | 'ruby'
          | 'olive'
          | 'sage'
          | 'slate'
          | 'sand'
          | 'gray'
          | 'mauve'
          | 'brown'
          | 'bronze'
          | 'gold'
          | 'red'
          | 'crimson'
          | 'tomato'
          | 'pink'
          | 'plum'
          | 'indigo'
          | 'iris'
          | 'violet'
          | 'purple'
          | null;
        secondary?:
          | 'ruby'
          | 'olive'
          | 'sage'
          | 'slate'
          | 'sand'
          | 'gray'
          | 'mauve'
          | 'brown'
          | 'bronze'
          | 'gold'
          | 'red'
          | 'crimson'
          | 'tomato'
          | 'pink'
          | 'plum'
          | 'indigo'
          | 'iris'
          | 'violet'
          | 'purple'
          | 'amber'
          | 'blue'
          | 'cyan'
          | 'grass'
          | 'green'
          | 'jade'
          | 'lime'
          | 'mint'
          | 'orange'
          | 'sky'
          | 'teal'
          | 'yellow'
          | null;
        statusLabel?: string;
      })
BadgeStatus
type BadgeStatus = 'info' | 'success' | 'warning' | 'danger'
StatusGlyphProps
type StatusGlyphProps = any
statusScales
type statusScales = { info: 'indigo'; success: 'green'; warning: 'amber'; danger: 'red' }
statusWords

The glyph’s accessible name: the status in words, so it is never shape or color alone.

type statusWords = Record<'info' | 'success' | 'warning' | 'danger', string>

Specification: DESIGN-SYSTEM.md §10.11 (badge, tag and chip) and §1.5.4 (status).