‹ components

ReactionBar

stablev1.0.0·open in canvas

Row of emoji-reaction pills with counts, plus a `+` picker. Tap = spring-pop.

Installnpx shadcn add @cids/reaction-bar
Live demo

Motion · tap to replay

honors reduced-motion

`--motion-spring` (250ms, overshoot) scales the emoji `1 → 1.3 → 1` on tap — the budgeted-playfulness moment (DESIGN.md → Identity). Cleared on `animationend` so repeated taps replay. Reduced-motion: the global reset collapses the animation.

Brand chip remounts on tap · highlighted tokens are named in this component's doc · spring is budgeted to human feedback only.

import { ReactionBar, type Reaction } from "@/design-system";

const [reactions, setReactions] = useState<Reaction[]>([
  { emoji: "♥", count: 12, mine: true },
]);

<ReactionBar
  reactions={reactions}
  onReact={(emoji) => toggleAndPersist(emoji)}  // counts are yours to update
/>

Tokens · live

Resolves in the active theme — flip the toggle above to verify.

States · from doc

Parsed from the doc. Interact with the live demo for hover/active.

**Default** — transparent pill`fg-muted` count.**Mine** — `bg-brand/10`count in `text-brand`.

Row of emoji-reaction pills with counts, plus a + picker. Tap = spring-pop.

Anatomy

 ♥12  🔥8  🧠4   +          ← pills h-44 hit area
 └┬┘              └ opens picker popover
  └ mine: bg-brand/10, count text-brand
                  ┌ ♥ 🔥 👀 🧠 😅 📈 ┐  ← picker, surface-bright
                  └──────────────────┘

Props

PropTypeDefaultNotes
reactionsReaction[]—{ emoji, count, mine? }. Counts/mine are owned by the caller.
onReact(emoji: string) => void—Fired on pill tap or picker choice.
pickerEmojisstring[]♥ 🔥 👀 🧠 😅 📈Emoji offered by the + picker.
classNamestring—Merged via cn.

Motion

--motion-spring (250ms, overshoot) scales the emoji 1 → 1.3 → 1 on tap — the budgeted-playfulness moment (DESIGN.md → Identity). Cleared on animationend so repeated taps replay. Reduced-motion: the global reset collapses the animation.

A11y

Self-contained: copy the folder into any Tailwind+React app, or use the install command above. Docs and this page render the same file on disk — they cannot drift.