Reactions

Pro

Emoji reactions under a message, a comment or a post. Each pill is a toggle with a count, and the add button opens the emoji picker. A soft halo pulses on the one you just added.

A
Ana Ruiz

The new onboarding flow is live for everyone. Signups are up 18% since this morning.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add reactions

Usage#

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Anatomy#

import { Reaction, ReactionAdd, Reactions } from "@/components/ui/reactions"<Reactions>  <Reaction emoji="👍" count={3} />  <ReactionAdd /></Reactions>

Yours#

A pressed pill is a reaction you made: it takes a stronger fill, a hairline ring and full ink. Clicking it again takes yours away, and a reaction nobody holds any more leaves the row. The tooltip names who reacted, you included, and never opens on touch.

The ring pulse#

Turning a reaction on plays a soft halo in the reading ink as the hit of the press: it leaves the pill’s edge and keeps travelling outward while it dissolves, about half a second in all. It is ink, not the accent, like the pressed pill it marks. The pill itself stays put. Only one pill pulses at a time. With reduced motion the halo appears in place and fades.

Adding from the picker#

ReactionAdd opens the Emoji Picker above the row. Picking an emoji calls onEmojiSelect; add yourself to that reaction and its pill pulses as it arrives, whether it is new or already in the row.

Sizes#

Without a count#

Leave count unset for a round, emoji-only pill, as in a quick-reaction bar. Give each one a label.

In a chat thread#

Marc Vidal
Pushed the fix for the export timeout. Reports over 10k rows finish in about four seconds now.
Laia Serra
Checked it on the finance workspace, works for me.
Pau Torres
Can we ship it with today's release?

API reference#

Reactions

The row, a div with role="group" named "Reactions". Owns the size and the one ring pulse the row plays at a time. Accepts className, merged last.

PropTypeDefaultDescription
size"sm" | "md"-Pill size: sm is 24px tall, md 28px. Follows the density when unset: compact gives sm, otherwise md.
childrenReactNode-Reaction pills, then a ReactionAdd at the end.
Data attributeDescription
data-slotreactions on the row.

Reaction

One reaction pill, built on Toggle (Radix). Pressed means the reaction is yours. Turning it on sends a soft ink halo off its edge like a wave. Accepts className, merged last.

PropTypeDefaultDescription
emoji*string-The emoji. Also the key the row uses to pulse the pill a picked emoji lands on.
countnumber-How many people reacted. Rolls when it changes. Leave unset for an emoji-only round pill.
tooltipReactNode-Who reacted, shown on hover ("Ana, Marc and you"). Never opens on touch.
labelstring"👍, 3 reactions"Accessible name. Built from emoji and count by default; aria-pressed says whether it is yours.
pressedboolean-Controlled state: whether the current person reacted with this emoji.
defaultPressedbooleanfalseInitial state when uncontrolled.
onPressedChange(pressed: boolean) => void-Called when the person adds or removes their reaction.
disabledbooleanfalseShows the reaction without letting anyone toggle it.
Data attributeDescription
data-stateon when the reaction is yours, off otherwise.
data-pulsingPresent while the ring pulses, for about half a second after the reaction is turned on or picked.
data-baretrue when there is no count, which makes the pill round.
data-slotreaction on the pill, reaction-emoji and reaction-count inside it, reaction-pulse on the halo layer.

ReactionAdd

The add-reaction button at the end of the row. Opens the Emoji Picker in a popover; the same ink halo as the pulse grows in and holds for as long as the picker is open. Accepts className, merged last.

PropTypeDefaultDescription
onEmojiSelect(emoji: string, datum: EmojiDatum) => void-Receives the emoji the person chose; its pill in the row pulses when it lands.
labelstring"Add reaction"Accessible name and tooltip.
iconReactNode<Smiley />Replaces the smiley glyph.
side"top" | "right" | "bottom" | "left""top"Preferred side of the picker; it flips when there is no room.
align"start" | "center" | "end""start"Alignment of the picker against the button.
presetsstring[]-The picker's frequently used row.
recentstring[]-Controlled recently used emoji.
storageKeystring | null"koala-emoji-recent"Where the picker remembers recent emoji. null keeps them in memory only.
containerHTMLElement | nulldocument.bodyElement the picker popover portals into.
Data attributeDescription
data-stateopen or closed, from the picker trigger.
data-bareAlways true: the button is round.
data-slotreaction-add on the button, reaction-ring on the ring while the picker is open.

FAQ#

You do. Reactions is controlled: keep who reacted with each emoji in your state, pass the count and whether it is yours, and update it in onPressedChange and onEmojiSelect.