Reactions
Acknowledge a post in one tap, with counts that roll.
pnpm dlx shadcn@latest add @uiarc/reactionsLive · keyboard ready
Offline drafts are here
Edits made on a flight or a patchy train now sync the moment you reconnect. When two people change the same field, both versions open side by side instead of one quietly overwriting the other.
- Lightweight acknowledgement on comments, posts, or release notes.
- Slack-style reaction pills with counts and a picker for new reactions.
- Use a reply field such as ai-composer when people need to say something specific.
- Use action-swap for a single like or follow toggle without counts.
- Use badge for static counts that people cannot change.
Installation
Add Reactions with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/reactionsAdds the component and its local dependencies, and installs @radix-ui/react-popover, motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:
example.tsx
import { Reactions } from "@/components/arc/reactions/reactions";import { Heart, PartyPopper, ThumbsUp } from "lucide-react"; const options = [ { id: "like", label: "Like", icon: ThumbsUp }, { id: "love", label: "Love", icon: Heart }, { id: "party", label: "Celebrate", icon: PartyPopper },]; export function CommentReactions() { return <Reactions options={options} defaultValue={[{ id: "like", count: 3, reacted: false }]} onValueChange={(_, change) => save(change)} />;}Reactions
A bar of reaction pills with counts and an add button that opens a picker tray.
PropTypeDefaultDescription
optionsRequiredReactionOption[]–Every reaction the picker offers: { id, label, icon: LucideIcon }.valueReaction[]–Controlled reactions: { id, count, reacted }. Pills keep this order; a count of zero leaves the bar.defaultValueReaction[][]Initial reactions when uncontrolled.onValueChange(next: Reaction[], change: { id: string; reacted: boolean }) => void–Called with the next list and the change that produced it.labelstring"Reactions"Accessible name for the bar.classNamestring–Extra class on the root.- EnterorSpace
- Toggles your reaction on a pill, or opens the picker from the add button.
- ArrowLeftorArrowRightorArrowUporArrowDown
- Moves between options in the picker, wrapping at the ends.
- HomeorEnd
- Jumps to the first or last option.
- Escape
- Closes the picker and returns focus to the add button.
- The bar is role="group"; each pill is a button with aria-pressed and a label like "Love, 4 reactions, including yours".
- The picker is a role="toolbar" with roving tabindex and labelled options; the add button is labelled "Add reaction".
- A role="status" region announces each change; a pill that leaves while focused hands focus to its neighbour or the add button.
- Pills scale in from a blur and reflow on a morph spring; the icon gets a velocity kick that stacks on quick taps, and digits roll in the direction of the count.
- The picker grows out of the add button while a shared highlight glides between options.
- Reduced motion, read only after hydration, swaps everything with short fades and no layout springs.
- The bar wraps onto new lines as pills are added, and its height springs to fit.
- The picker opens in a Radix popover, so it repositions near viewport edges.
- Hover highlights in the picker follow the mouse only; touch taps select directly.
- Pills use layout position animation and count digits roll individually; fine for a handful of reactions per item.
- In long comment threads each bar runs its own ResizeObserver, so avoid rendering hundreds at once.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for lightweight acknowledgement on comments, posts, or release notes. When people need to say something specific, add a reply field instead.
- Icons must be Lucide component types, not elements. Persist the change from onValueChange and control value when counts come from the server.
The full library index for assistants is at /llms.txt.