Editor: Add emoji reactions to Notes#75148
Conversation
Introduce a new component that displays a horizontal row of emoji buttons for adding reactions to notes. Features include: - Curated emoji set: 👍 👎 ❤️ 🎉 😄 😕 👀 🚀 - Keyboard navigation with arrow keys, Home, and End - Accessible with role="listbox" and role="option" Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduce a component that displays current reactions with counts as pill-shaped buttons. Features include: - Shows reaction counts for each emoji - Highlights user's own reactions with distinct styling - Click to toggle (add/remove) reaction - "+" button opens emoji picker dropdown Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduce a popover component that shows who reacted and when. Features include: - Displays reactions grouped by emoji - Shows user avatars and names - Uses humanTimeDiff() for relative timestamps (e.g., "3 days ago") - Fetches user data for all reactors Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend the useBlockCommentsActions hook with three new functions:
- onAddReaction: Add a reaction to a comment
- onRemoveReaction: Remove user's reaction from a comment
- onToggleReaction: Toggle reaction (add if not present, remove if present)
Reactions are stored in comment meta._wp_reactions with structure:
{ emoji: [{ userId, timestamp }] }
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Connect the reaction components to the Notes sidebar: - Import and render ReactionDisplay in CommentBoard - Add ReactionDetailsPopover for viewing reaction details - Add "See emoji reaction details" menu action - Pass onToggleReaction through component hierarchy - Get current user ID for highlighting own reactions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add SCSS styles for: - Reactions container with flexbox layout - Pill-shaped reaction buttons with active state - Add reaction button with dashed border - Emoji picker dropdown - Reaction details popover with user avatars Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive E2E tests for the emoji reactions feature: - can add an emoji reaction to a note - can remove own emoji reaction by clicking it - can see emoji reaction details - reaction buttons are keyboard accessible - can add multiple different reactions to same note Also adds addReactionToComment helper to BlockCommentUtils. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: +2.49 kB (+0.04%) Total Size: 6.85 MB
ℹ️ View Unchanged
|
Resolve merge conflicts with trunk's selectedNote editor state changes (#75177) while preserving emoji reaction features. Fix all 5 emoji reaction E2E tests that were timing out because the Dropdown popover was stealing focus from the thread, triggering the onBlur handler which collapsed the note and unmounted the emoji picker. - Add focusOnMount: false to the reaction Dropdown popoverProps - Add popover focus check to the thread onBlur handler - Update addReactionToComment E2E helper to wait for the emoji picker Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…yling Replace the plus icon with a Google Docs-inspired smiley face SVG, change focusOnMount to 'firstElement' so the emoji picker captures focus and prevents the note from collapsing, and restyle the button to be perfectly round with a clean white background that appears on hover. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the "Add reaction" smiley button from below the note content to the upper-right header area alongside the resolve and actions buttons. Also register _wp_reactions as comment meta in PHP so the REST API accepts it, and fix the 500 error caused by spreading all comment meta (including potentially invalid _wp_note_status) when saving reactions. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Add variant="tertiary" to the reaction pill Button components so the WordPress default dark button styling doesn't override the custom light gray background. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
The Button component automatically adds the is-pressed class when aria-pressed is true, which sets a dark background (#1E1E1E). Override with matching specificity to keep the light blue active state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase height to 32px, use equal padding on all sides, and reduce gap between emoji and count to bring the aspect ratio closer to 1:1. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Thank you, @adamsilverstein! Left some initial code reviews. I think we're moving in the right direction. This needs real design review, but here are my thoughts just in case :) While I like the reaction details dropdown, I'm not sure if it's really needed. Maybe we should just do what GH does: a reaction list with tooltips that include extra info. cc @jasmussen |
| // Get current user from the store. | ||
| const currentUser = | ||
| registry.select( coreStore ).getCurrentUser() || {}; | ||
| const userId = currentUser.id; | ||
|
|
||
| if ( ! userId ) { | ||
| throw new Error( __( 'You must be logged in to react.' ) ); | ||
| } | ||
|
|
||
| // Get current comment data. | ||
| const comment = registry | ||
| .select( coreStore ) | ||
| .getEntityRecord( 'root', 'comment', commentId ); | ||
|
|
||
| if ( ! comment ) { | ||
| throw new Error( __( 'Comment not found.' ) ); | ||
| } |
There was a problem hiding this comment.
The same checks are also done inside onRemoveReaction|onAddReaction. It seems toggle is just a wrapper. I think we can remove these checks.
There was a problem hiding this comment.
Happy to remove, probably over-defensive.
With collaborative editing, it is possible another user has deleted a note right when you tried to add a reaction in such a way that the comment is no longer available here? I guess the answer might be no, but wanted to ask the question because if it is possible, leaving the checks would guard against this.
There was a problem hiding this comment.
@Mamaduka ping on this outstanding feedback, let me know what you think.
The button was absolutely positioned over the note text, which could obscure content and was not discoverable by keyboard. It now sits inline alongside reaction pills, always visible when the note is expanded.
|
Tried moving the reaction button below the note content, where the emoji's appear, in 007854e |
@joedolson I looked into this a bit more... The AddReactionButton uses the Menu component (Ariakit wrapper), which follows the ARIA menu button pattern: on keyboard open, focus moves to the first menu item. This means the trigger button loses focus To get the behavior you are suggesting, we would need to refactor AddReactionButton to use a Button that toggles isOpen state on click, with a Popover that shows/hides accordingly. Happy to work on that if you feel it would be beneficial (could be after merge though as its an implementation detail). |
I will look into this. One trick I found for debugging these temporary states is to add a delayed debugger command in the console:
then open the element and wait for the debugger to fire. |
Check document.hasFocus() in onBlur handlers so that switching browser tabs or windows does not deselect the active note, preventing unintended state resets.
I tried fixing this in dcf7103, let me know if that helps @joedolson! |
|
Flaky tests detected in dcf7103. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/22088476882
|
|
I think design and functionality-wise, this PR is good to go. Unless @jasmussen or @joedolson wants more follow-ups. What worries me is the storage mechanism (comment meta vs. comment type). Once we choose it, I think it will be hard to migrate, so we'll be stuck with it. The generic reaction type proposal by @swissspidy is a good idea, but requires more work on the REST API side, which I would be hesitant to ship in beta. tl;dr I think the feature might be ready for the plugin, but not the core. cc @annezazu, @mtias, what do you think? |
|
No feedback that need block this, I'll defer to you all. But to consider in followups, the precise appearance and style of the emoji button has felt slightly off for me, so I wanted to just visually explore the territory. The main concern is to reduce the amount of custom CSS we need to write for this, the more we can use the systems that exist, the better for maintenance, coherence, accessibility. This is also considering things like future dark mode support, etc, where existing buttons can evolve to have color token support so their strokes and styles would update automatically. All custom CSS would have to be rewritten. In any case, the initial instinct and still one I think is good, is this one:
The emoji button always sits as just a plain 24x24 icon button next to other actions for each comment. The main concern is the text getting elided. I think that's okay with the name, and there should be room for the time-since based datestamp, even in longer languages such as German ("vor 51 Minuten"). But even if that text needs to wrap, having the actions in the top right of each comment still feels like the simplest and cleanest solution. The "Slack" model, in a sense. An alternative is, as I previously noted, to have it below, where the reactions will show up, the "GitHub" model:
The details would matter here, gray-600 inside a "small" 24x24 button, but the icon would be unscaled still, the full 24x24 icon. At the moment it's in a 28x28 button and the icon itself is 20x20. I acknowledge this feels a bit bare, perhaps especially once you see pill shaped reactions to the right of it. So going full GitHub might be an option:
Here the details would matter too, as far as systematizing. We generally don't scale icons down if we can avoid it, as the icons look best in their designed-for sizes (24x24). But in some cases we have scaled them down, Badge comes to mind. That actually sets a non-integer scale of 16x16, whereas 18x18 would've been a precise 0.75x scale and theoretically interpolate better. But in the above the icon is 16x16 inside a 24x24 circular button. Such circular buttons don't really exist in the system, so it's a bit of a departure in that sense, and one we'd want to be mindful of as the componentry evolves. But those are some options to consider in followups. I still have a personal preference for the Slack model, option 1, but it's not strongly felt, and hopefully these options are helpful in unblocking. |
I also prefer option 1, but am also easily swayed by the overlapping the name issue argument 🤷🏼 |
|
Yep we want to avoid the overlapping stuff, but that's ideally done through either allowing eliding of the text, or letting it wrap. Not for this PR, but worth considering! |
This reverts commit dcf7103.
That's interesting. The reason I raised that issue was because that is not what happened in my testing; the focus stayed on the trigger, and I had to hit |
@ellatrix do you have any thoughts here? IMO, if we can't determine something that feels good/right for storage, we should not ship for 7.0 and can look to a future release. I want to make hard to reverse decisions slowly :) |
|
My initial reaction (no pun intended) was: a new comment type sounds better to me because we're awkwardly recreating date and author fields in comment meta. A reaction is just a small comment to another comment (through parent ID).
@adamsilverstein Exactly, a reaction is a response. It's not a note, it's a separate comment type. Isn't that an argument for using comments?
We already have to do that for notes, no?
Since it's a new comment type, it's not tied to notes so it can be reused for all other comments? That all said, when I asked Claude about this, it totally rejected the idea of a comment type due to performance concerns, a lot of useless fields for reactions, admin pollution, count inflation, etc. After telling it that we could adjust core itself it kind of seemed to be more in favor of comments. Maybe this all needs some deeper thought from multiple people and perspectives. Since it's irreversible and close to the deadline for 7.0, I'd lean on the side of waiting until the next release, but I'd love to hear more opinions. If we'd decide to try it with a new comment type, there's probably not enough time to try it? |
|
@adamsilverstein I see what's unexpected about the Ariakit menu interaction; it's fine as it is, and works well for screen readers - but it is confusing for sighted users, because the menu doesn't give any indication that it's focused. The actual behavior is that toggling the control focuses the menu container. You can't actually navigate the menu with the arrow keys until you go inside the container, however, which requires an additional tab. I think that if the menu containing the emoji had a focus ring to make it clear that it had received focus, this would be better communicated. |
|
Regarding storage, I have decided to go with the alternate custom comment type. Unless someone is strongly opposed, this seems like the overall preferred solution. Please leave additional feedback and perform any testing on #75549 |
Remove the PHP filter (note_reaction_emojis) and editor settings injection for customizing the reaction emoji set. The JS components now use the hardcoded REACTION_EMOJIS list directly again. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Closing in favor of #75549 which uses the alternate storage mechanism suggested by @swissspidy. |
Add a docblock to lib/compat/wordpress-7.1/block-comments.php explaining why reactions use a custom 'reaction' comment type instead of comment meta: free authorship/timestamps from comment APIs, generic type that can attach to other resources, and per-row writes to avoid serialized-meta races. Links to the discussion in PRs #75549 and #75148.



Summary
Adds emoji reactions to Notes in the Gutenberg editor, allowing users to react with a curated emoji set, see who reacted and when, and remove their own reactions.
Closes #75144
Features
Data Model
Reactions are stored in comment
metafield:New Files
reaction-emoji-picker.jsreaction-display.jsreaction-details-popover.jsTest plan
E2E Tests
New E2E tests added in
block-comments.spec.js:can add an emoji reaction to a notecan remove own emoji reaction by clicking itcan see emoji reaction detailsreaction buttons are keyboard accessiblecan add multiple different reactions to same noteScreenshots
Screen.Recording.480.2026-02-05.at.4.24.36.PM.mov
AI Use
I used Claude caude to author most of the code in this PR which I have also tested and reviewed manually.