Skip to content
uiify

Badge

Short label for a state, category, or count.

Browsers
Chrome 123+Firefox 121+Safari 17.5+
Tier
0
Bundle compressed
201 B
Forced layout budget
0 ms
Axe budget
0
SSR compatible
Yes
Published contract
Test harness

Playground

Badge

Ready
import { Badge } from "@gunkin/uiify";

export default function Example() {
  return <Badge className="">Ready</Badge>;
}
@layer components {
  [data-uiify-badge] {
    display: inline-flex;
    align-items: center;
    padding-block: 0.25rem;
    padding-inline: 0.625rem;
    border-radius: var(--radius-full);
    background: var(--secondary);
    color: var(--secondary-foreground);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    line-height: 1.25;
  }

  [data-uiify-badge][data-size="sm"] {
    padding-block: 0.125rem;
    padding-inline: 0.5rem;
    font-size: var(--text-xs);
  }

  [data-uiify-badge][data-size="md"] {
    padding-block: 0.25rem;
    padding-inline: 0.625rem;
  }

  [data-uiify-badge][data-size="lg"] {
    padding-block: 0.375rem;
    padding-inline: 0.75rem;
    font-size: var(--text-base);
  }

  [data-uiify-badge][data-variant="success"] {
    background: color-mix(in oklch, var(--success) 16%, var(--background));
    color: var(--foreground);
  }

  [data-uiify-badge][data-variant="warning"] {
    background: color-mix(in oklch, var(--warning) 16%, var(--background));
    color: var(--foreground);
  }

  [data-uiify-badge][data-variant="destructive"] {
    background: color-mix(in oklch, var(--destructive) 12%, var(--background));
    color: var(--foreground);
  }
}
import { Badge } from "@gunkin/uiify";

export default function Example() {
  return (
    <Badge
      className="
        inline-flex items-center [padding-block:0.25rem] [padding-inline:0.625rem] rounded-[var(--radius-full)]
        bg-secondary text-secondary-foreground text-sm font-[number:var(--weight-medium)] [line-height:1.25]
        data-[size=sm]:[padding-block:0.125rem] data-[size=sm]:[padding-inline:0.5rem] data-[size=sm]:text-xs
        data-[size=md]:[padding-block:0.25rem] data-[size=md]:[padding-inline:0.625rem]
        data-[size=lg]:[padding-block:0.375rem] data-[size=lg]:[padding-inline:0.75rem] data-[size=lg]:text-base
        data-[variant=success]:[background:color-mix(in_oklch,_var(--success)_16%,_var(--background))]
        data-[variant=success]:text-foreground
        data-[variant=warning]:[background:color-mix(in_oklch,_var(--warning)_16%,_var(--background))]
        data-[variant=warning]:text-foreground
        data-[variant=destructive]:[background:color-mix(in_oklch,_var(--destructive)_12%,_var(--background))]
        data-[variant=destructive]:text-foreground
      "
    >
      Ready
    </Badge>
  );
}
/* app.css */

@layer reset, ui, app, tokens, base, demo, components, utilities, theme;

@import "@gunkin/uiify/styles/reset";

@import "@gunkin/uiify/components/behavior.css";

@import "@gunkin/uiify/styles/tokens";

@import "@gunkin/uiify/styles/tailwind";

@import "tailwindcss/utilities.css";

@theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }

@source inline('inline-flex items-center [padding-block:0.25rem] [padding-inline:0.625rem] rounded-[var(--radius-full)] bg-secondary text-secondary-foreground text-sm font-[number:var(--weight-medium)] [line-height:1.25] data-[size=sm]:[padding-block:0.125rem] data-[size=sm]:[padding-inline:0.5rem] data-[size=sm]:text-xs data-[size=md]:[padding-block:0.25rem] data-[size=md]:[padding-inline:0.625rem] data-[size=lg]:[padding-block:0.375rem] data-[size=lg]:[padding-inline:0.75rem] data-[size=lg]:text-base data-[variant=success]:[background:color-mix(in_oklch,_var(--success)_16%,_var(--background))] data-[variant=success]:text-foreground data-[variant=warning]:[background:color-mix(in_oklch,_var(--warning)_16%,_var(--background))] data-[variant=warning]:text-foreground data-[variant=destructive]:[background:color-mix(in_oklch,_var(--destructive)_12%,_var(--background))] data-[variant=destructive]:text-foreground');

@layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }

/* Authored animation and registered properties used by the Tailwind skin.
 * Visual rules belong in utility recipes; only at-rule definitions live here. */
@layer components {
  @keyframes uiify-presence-in {
    from {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@layer components {
  @keyframes uiify-presence-out {
    to {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --uiify-spinner-length {
  syntax: "<angle>";
  inherits: false;
  initial-value: 36deg;
}

@layer components {
  @keyframes uiify-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }
}

@layer components {
  @keyframes uiify-spinner-orbit {
    0% {
      --uiify-spinner-tail: 0deg;
      --uiify-spinner-length: 36deg;
    }

    50% {
      --uiify-spinner-tail: 90deg;
      --uiify-spinner-length: 324deg;
    }

    100% {
      --uiify-spinner-tail: 360deg;
      --uiify-spinner-length: 36deg;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-pulse {
    50% {
      opacity: 0.45;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-shimmer {
    to {
      background-position: -200% 0;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-reveal {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@property --line-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-prev-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-count {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}

@property --line-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  @keyframes uiify-otp-input-caret-blink {
    50% {
      opacity: 0;
    }
  }
}

Examples

Status labels

Use visible words to convey state; color is a supporting cue.

DraftReadyReviewBlocked
import { Badge } from "@gunkin/uiify";

export default function Example() {
  return (
    <>
      <Badge variant="secondary">Draft</Badge>
      <Badge variant="success">Ready</Badge>
      <Badge variant="warning">Review</Badge>
      <Badge variant="destructive">Blocked</Badge>
    </>
  );
}

API

Badge

PropTypeDefaultDescription
childrenReactNode—Text shown inside the badge.
variant"secondary" | "success" | "warning" | "destructive"—Visual meaning written to data-variant; keep status understandable in text.
size"sm" | "md" | "lg"—Visual scale written to data-size; omitted when unset.
asElementType"span"Native element or component used for the root.
classNamestring—Class applied to the root element.
styleCSSProperties—Native root styles.
refRef<HTMLElement>—Ref forwarded to the rendered root element.
renderReactElement | ((props, state) => ReactElement)—Replace the rendered element while keeping behavior and accessibility wiring.

Keyboard

KeyAction

Accessibility

Static text marker with no role or keyboard behavior. Keep its meaning in visible words and do not use it as a control.

Styling hooks

data-uiify-badgedata-variantdata-size