Reaction bar
Emoji reactions with counts. Press one to add or take back yours; hover or focus to see who reacted.
Release 2.4 is out. Thanks everyone who tested the beta over the weekend.
You, Jonas Berg, Priya Raman and Leo Martins reacted with thumbs upSana Haddad reacted with party popperKofi Mensah and Inès Laurent reacted with eyes
Usage
use hydroxy_leptos::reaction_bar::{Reaction, ReactionBar, toggle};
use leptos::prelude::*;
#[component]
pub fn Demo() -> impl IntoView {
let reactions = RwSignal::new(vec![
Reaction::new("👍", "thumbs up", &["Jonas Berg", "Priya Raman", "Leo Martins"]).mine(),
Reaction::new("🎉", "party popper", &["Sana Haddad"]),
Reaction::new("👀", "eyes", &["Kofi Mensah", "Inès Laurent"]),
]);
// A real app would store these per user, say in localStorage or the profile.
let recent = RwSignal::new(vec!["🚀".to_string(), "🙏".to_string(), "✅".to_string()]);
view! {
<div style="display: grid; gap: var(--space-3); max-width: 460px; padding: var(--space-4); border-radius: var(--radius-lg); background: var(--surface-sunken);">
<p style="margin: 0; font: var(--text-body); color: var(--text-1);">
"Release 2.4 is out. Thanks everyone who tested the beta over the weekend."
</p>
<ReactionBar
reactions=reactions
on_toggle=move |(emoji, name): (String, String)| reactions.update(|r| toggle(r, &emoji, &name))
recent=recent
on_recent_change=move |list| recent.set(list)
/>
</div>
}
}use dioxus::prelude::*;
use hydroxy_dioxus::reaction_bar::{Reaction, ReactionBar, toggle};
#[component]
pub fn ReactionBarDemo() -> Element {
let mut reactions = use_signal(|| {
vec![
Reaction::new("👍", "thumbs up", &["Jonas Berg", "Priya Raman", "Leo Martins"]).mine(),
Reaction::new("🎉", "party popper", &["Sana Haddad"]),
Reaction::new("👀", "eyes", &["Kofi Mensah", "Inès Laurent"]),
]
});
// A real app would store these per user, say in the profile.
let mut recent = use_signal(|| vec!["🚀".to_string(), "🙏".to_string(), "✅".to_string()]);
rsx! {
div { style: "display: grid; gap: var(--space-3); max-width: 460px; padding: var(--space-4); border: 1px solid var(--border-1); border-radius: var(--radius-lg); background: var(--surface-card);",
p { style: "margin: 0; font: var(--text-body); color: var(--text-1);",
"Release 2.4 is out. Thanks everyone who tested the beta over the weekend."
}
ReactionBar {
reactions: reactions(),
on_toggle: move |(emoji, name): (String, String)| toggle(&mut reactions.write(), &emoji, &name),
recent: recent(),
on_recent_change: move |list| recent.set(list),
}
}
}
}
Anatomy
| Component | data-part | Renders |
|---|---|---|
ReactionBar | root | role=group, named "Reactions" |
ReactionBar | chip | Toggle button with aria-pressed; named "thumbs up, 3 reactions" |
ReactionBar | tip | role=tooltip describing the chip: "You, Jonas and 2 others reacted with thumbs up" |
ReactionBar | add | Opens the emoji picker in a native popover |
ReactionBar | picker | Popover holding an EmojiPicker; focus starts in its search |
ReactionBar | status | Polite live region: "Added party popper" |
Keyboard
| Key | Does |
|---|---|
Enter / Space | On a chip: add or remove your reaction |
Tab | Move between chips and the add button |
Escape | Close the picker and return to the add button |
Props
| Prop | Type | Notes |
|---|---|---|
reactions | Vec<Reaction> | Required. Emoji, name, other people, whether you reacted |
on_toggle | Callback<(String, String)> | Emoji and name to toggle. reaction_bar::toggle applies it to a Vec |
recent | Vec<String> | Recently used emoji for the picker |
on_recent_change | Callback<Vec<String>> | Store the picker's new recent list |
skin_tone | Option<SkinTone> | Controlled skin tone for the picker |
on_skin_tone_change | Callback<SkinTone> | Store the chosen tone |
label | String | Group name. Default "Reactions" |