Glin UI
Primitive / Atom

Counter

Numeric badge that compacts overflow values like 99+.

Edit on GitHub

Installation

Install from
pnpm dlx @glinui/cli@latest add counter

Prefer the package?

Usage

Variants

Every vocabulary variant on the default tone. Omit variant to follow the ambient design style.

12121212121212
import { Counter } from "@glinui/ui"
export function CounterVariantsDemo() {
return (
<div className="flex flex-wrap items-center gap-3">
<Counter variant="glinr" value={12} />
<Counter variant="solid" value={12} />
<Counter variant="plain" value={12} />
<Counter variant="soft" value={12} />
<Counter variant="outline" value={12} />
<Counter variant="ghost" value={12} />
<Counter variant="gradient" value={12} />
</div>
)
}

Sizes and badges

Sizes, and counters on a button and an icon.

44299+
99+
import { Bell, Envelope } from "@phosphor-icons/react"
import { Button, Counter, IconFrame } from "@glinui/ui"
export function Demo() {
return (
<div className="flex flex-wrap items-center gap-6">
<div className="flex items-center gap-2">
<Counter value={4} size="sm" />
<Counter value={42} size="md" />
<Counter value={420} size="lg" />
</div>
<Button variant="outline" size="sm" className="gap-2">
<Bell aria-hidden className="size-4" />
Notifications
<Counter value={7} tone="danger" variant="solid" size="sm" />
</Button>
<span className="relative inline-flex">
<IconFrame size="lg"><Envelope aria-hidden className="size-5" /></IconFrame>
<Counter value={128} max={99} tone="danger" variant="solid" size="sm" className="absolute -right-2 -top-2" aria-label="128 unread" />
</span>
</div>
)
}

Overflow

When `value` exceeds `max` (default `99`), the display collapses to `max+` to prevent layout shift.

import { Counter } from "@glinui/ui"

export function CounterOverflowDemo() {
  return (
    <div className="flex items-center gap-4">
      <Counter value={42} />
      <Counter value={99} />
      <Counter value={150} />
      <Counter value={1200} />
    </div>
  )
}

Custom Max

Override the collapse threshold with `max` to suit different contexts, notification trays, cart counts, or mention lists.

import { Counter } from "@glinui/ui"

export function CounterCustomMaxDemo() {
  return (
    <div className="flex items-center gap-4">
      <Counter value={42} max={50} />
      <Counter value={55} max={50} />
      <Counter value={9} max={9} />
      <Counter value={10} max={9} />
    </div>
  )
}

Variants

import { Counter } from "@glinui/ui"

export function CounterVariantDemo() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <Counter value={7} variant="default" />
      <Counter value={7} variant="glass" />
      <Counter value={7} variant="outline" />
      <Counter value={7} variant="ghost" />
    </div>
  )
}

Sizes

import { Counter } from "@glinui/ui"

export function CounterSizeDemo() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <Counter value={12} size="sm" />
      <Counter value={12} size="md" />
      <Counter value={12} size="lg" />
    </div>
  )
}

Accessibility

  • Use `aria-label` to describe what the count represents.
  • `Counter` should be accompanied by a visible label in its surrounding context (e.g., "Notifications: 12") so the number is not the sole conveyor of meaning.
  • When used as a live notification badge, wrap the containing element with `aria-live="polite"` so screen readers announce value changes.
  • The truncated `max+` format must be interpreted from context, add an `aria-label` to clarify if necessary (e.g., `aria-label="More than 99 notifications"`).
  • Do not rely on the counter's color alone to communicate urgency; pair with surrounding labels.

ARIA Attributes

  • `aria-live="polite"` for dynamically updating counts

Reduced Motion

Counter updates are static by default with no animated value tweening.

`Counter` is a static numeric display with no animation. No reduced-motion considerations apply.

API Reference

PropTypeRequiredDefaultDescription
valuenumberYes-Current numeric value.
maxnumberNo99Maximum before collapsing into `max+` format.
variantSurfaceVariant | "default" | "primary" | "secondary" | "destructive" | "success" | "warning" | "info" | "raised" | "frosted"Noambient (glinr)Surface variant. Omit to follow the ambient design style (glinr by default, plain for minimal, glass for glass).
toneSurfaceToneNoneutralColour tone for the vocabulary variants.
size"sm" | "md" | "lg"NomdCounter density.

Source

Import directly from the package or browse the source on GitHub. Click any file to view it.

Import

import { Counter } from "@glinui/ui"

Source Files

Dependencies

@glinui/ui

Generated API Snapshot

Beta

Auto-extracted from TypeScript source in packages/ui/src/components/counter.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.

Generated: 2026-10-08T01:41:21.546Z · Full index: /docs/api-metadata

Primary Props Type

CounterProps

CounterProps

PropTypeRequiredDefaultDescription
maxnumberNo99-
size"sm" | "md" | "lg"No--
toneSurfaceToneNo--
valuenumberYes--
variantSurfaceVariant | "default" | "primary" | "secondary" | "destructive" | "success" | "warning" | "info" | "raised" | "frosted"No-Visual variant. Omit for the ambient design style (glinr by default).