Reactions
Slack-style emoji reactions — pills with counts that toggle, a card naming who reacted, and an add button with quick reactions.
- Status
- Since
0.23.37- Accessibility pattern
- toggle buttons with aria-pressed, labelled group
Last updated
Install
Add Reactions from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/reactionsThe same command installs the registry items it composes: @vegastack/button, @vegastack/emoji-picker, @vegastack/hover-card.
Usage
import { Reactions, toggleReaction } from "@/components/ui/reactions";
<Reactions
reactions={reactions}
onToggle={(emoji) => setReactions((rs) => toggleReaction(rs, emoji, me))}
/>;Each pill shows an emoji and its count. It is tinted and pressed when the viewer reacted, and a click toggles it. Hover a pill to see who reacted, for example "Neha Kapoor, Arjun Mehta and 3 others reacted with :thumbs_up:". People who are no longer active are marked "(Inactive)".
The ghost "Add reaction" button opens the compact EmojiPicker
with a quick row: 👍 ❤️ 😄 🎉 👀 🙏. Picking an emoji you already reacted with does nothing.
The host owns the data. onToggle may return a promise: the pill stays busy until it settles,
and repeat clicks are ignored meanwhile. toggleReaction is the pure update for an optimistic
change; on failure, restore the previous list and show a toast.
Anatomy
Examples
No reactions yet
Read-only
Without onToggle there is no add button, and pills only show who reacted.
Fewer names
maxUsersShown caps the names in the card; the rest become "and N others".
Optimistic with rollback
The pill flips at once and stays busy until the promise settles. Here 👀 fails and rolls back.
Add button alone
ReactionAdd is the button CommentItem puts in its hover actions.
In comments
CommentItem and CommentList take onReactionToggle and read each comment's reactions; see
Comments.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
reactions* | ReactionData[] | — | The reactions, in display order. Zero-count entries are skipped. |
className | string | — | Classes for the row. |
maxUsersShown | number | 10 | Names listed in a pill's card before "and N others". |
onToggle | MaybeAsync<[emoji: string]> | — | Add or remove the viewer's reaction; may return a promise. |
quickReactions | string[] | QUICK_REACTIONS | The picker's quick row. |
showAdd | boolean | true | Show the "Add reaction" button (needs onToggle). |
Data attributes and CSS variables on Reactions
| Attribute | Values |
|---|---|
data-slot | "reactions" |
| Prop | Type | Default | Description |
|---|---|---|---|
count* | number | — | How many people reacted with it. |
emoji* | string | — | The emoji character. |
reacted* | boolean | — | The viewer is one of them — the pill is tinted and pressed. |
users* | ReactionUser[] | — | Who reacted, oldest first (may be fewer than count). |
| Prop | Type | Default | Description |
|---|---|---|---|
id* | string | — | Stable id. |
name* | string | — | Display name. |
inactive | boolean | false | No longer active — the name is marked "(Inactive)". |
Accessibility
- The row is a group named "Reactions".
- Each pill is a toggle button with
aria-pressed, named with the emoji and count, for example "thumbs up 5, react". - A pill waiting on its promise sets
aria-busy. - The add button is named "Add reaction". The picker's quick row, category bar and grid each take one tab stop and move with the arrow keys.
| Key | Action |
|---|---|
| Enter / Space | Toggle a pill, or open the picker |
| ← / → | Move within the picker's rows and grid |
| Esc | Close the picker |
| Contract | States tested |
|---|---|
| Behaviour | default, reacted, busy, hover-card, add |
| Accessibility | labeled, pressed, browser-accessibility-test |
| Visual | default, reacted |
Do / Don't
Comments
A record's comments — a list with a count, an Oldest or Newest first toggle, skeleton and empty states, in-place editing, and a Linear-style composer.
Settings Row
A settings layout — titled sections, a flattened Card grouping label-plus-control rows, for building account, workspace, and preference screens.