Micro-feedback collection components for gathering quick user feedback without interrupting the user's workflow.
Inspired by Notion's page reactions, GitHub's "Was this helpful?" pattern, Intercom's CSAT survey, and Linear's NPS widget.
Pure HEEx — no JavaScript hooks required. All state managed server-side via LiveView assigns and phx-click events.
Sub-components
| Component | Purpose |
|---|---|
feedback_thumb/1 | Single thumbs-up "Was this helpful?" button |
feedback_reaction/1 | Emoji/icon reaction bar (👍 ❤️ 😂 😮 😢 😡) |
feedback_nps/1 | Net Promoter Score 0–10 scale widget |
feedback_survey_card/1 | "Was this helpful?" card with Yes/No and optional comment |
Thumbs up (docs helpful)
<.feedback_thumb
helpful={@page_helpful}
count={@helpful_count}
phx-click="toggle_helpful"
/>Emoji reactions
<.feedback_reaction
reactions={@reactions}
current_reaction={@my_reaction}
phx-value-reaction="..."
phx-click="react"
/>NPS score
<.feedback_nps
selected={@nps_score}
phx-click="submit_nps"
phx-value-score="..."
/>Survey card
<.feedback_survey_card
:if={!@feedback_submitted}
title="Was this article helpful?"
phx-click-yes="feedback_yes"
phx-click-no="feedback_no"
/>
Summary
Functions
Renders a Net Promoter Score (NPS) 0–10 rating widget.
Renders an emoji reaction bar.
Renders a compact "Was this helpful?" survey card.
Renders a single "thumbs up / helpful" feedback button.
Functions
Renders a Net Promoter Score (NPS) 0–10 rating widget.
Wire phx-click and phx-value-score at the wrapper level or on each button.
Scores 0–6 are Detractors (red), 7–8 Passives (amber), 9–10 Promoters (green).
Example
<.feedback_nps
question="How likely are you to recommend PhiaUI?"
selected={@nps_score}
phx-click="submit_nps"
/>
# LiveView handler
def handle_event("submit_nps", %{"score" => score}, socket) do
{:noreply, assign(socket, nps_score: String.to_integer(score))}
endAttributes
selected(:any) - Currently selected score (0–10), ornilif not yet answered. Defaults tonil.question(:string) - The NPS question displayed above the scale. Defaults to"How likely are you to recommend us to a friend?".class(:string) - Additional CSS classes. Defaults tonil.- Global attributes are accepted. HTML attrs forwarded to the wrapper. Add
phx-clickhere.
Renders an emoji reaction bar.
Each reaction button shows the emoji + count. The active reaction (matching
:current_reaction) is highlighted. Wire phx-click and phx-value-reaction
at the wrapper level for event delegation.
Example
<.feedback_reaction
reactions={[
%{emoji: "👍", count: 14, value: "like"},
%{emoji: "❤️", count: 7, value: "love"},
%{emoji: "😂", count: 3, value: "laugh"},
%{emoji: "😮", count: 2, value: "wow"}
]}
current_reaction={@my_reaction}
phx-click="react"
/>Attributes
reactions(:list) - List of reaction maps. Each map::emoji(string) — the emoji character or label:count(integer) — current count:value(string) — value sent as phx-value-reaction
Example:
[%{emoji: "👍", count: 12, value: "like"}]Defaults to
[].current_reaction(:string) - The:valueof the reaction the current user has selected (if any). Defaults tonil.class(:string) - Additional CSS classes. Defaults tonil.Global attributes are accepted. HTML attrs forwarded to the wrapper
<div>. Addphx-clickhere.
Renders a compact "Was this helpful?" survey card.
Provides Yes/No buttons with phx-click-yes and phx-click-no support.
Combine with a LiveView assign to swap the card content after answering.
Example
<.feedback_survey_card
:if={!@feedback_submitted}
title="Was this article helpful?"
phx-click-yes="feedback_yes"
phx-click-no="feedback_no"
/>
<div :if={@feedback_submitted} class="text-sm text-muted-foreground text-center py-4">
Thank you for your feedback!
</div>Attributes
title(:string) - Survey question displayed as the card title. Defaults to"Was this helpful?".description(:string) - Optional sub-text below the title. Defaults tonil.yes_label(:string) - Label for the positive response. Defaults to"Yes".no_label(:string) - Label for the negative response. Defaults to"No".class(:string) - Additional CSS classes. Defaults tonil.- Global attributes are accepted. HTML attrs forwarded to the card
<div>.
Slots
after_answer- Content to render after the user answers (e.g. thank-you message). Wire using:if.
Renders a single "thumbs up / helpful" feedback button.
Commonly used at the bottom of documentation pages, support articles,
and knowledge base entries. State is toggled server-side via phx-click.
Example
<.feedback_thumb helpful={@helpful} count={@count} phx-click="toggle_helpful" />Attributes
helpful(:boolean) - Whether the current user has marked as helpful. Defaults tofalse.count(:integer) - Optional count of people who found it helpful. Defaults tonil.label(:string) - Button label text. Defaults to"Helpful".class(:string) - Additional CSS classes. Defaults tonil.- Global attributes are accepted. HTML attrs forwarded to the
<button>.