Selectable subtle 44px icon controls for copying, reading aloud, rating through a combined feedback menu, and sharing an assistant response.
Preview
In action
Act on an assistant response
AssistantComplete
The brief is ready for review. It names Mina as the owner, gives the next step a date, and links three supporting sources.
Four quiet controls keep the response in focus: copy, read aloud, rate, and share. The combined thumbs icon opens helpful and unhelpful choices; choose the checked item again to clear it.
The action bar composes subtle icon buttons from the library. Reading aloud uses browser speech when available. Feedback stays in this example, and sharing uses the browser share sheet or copies the response.
When to use
Use it for
Place in the actions slot of Response and supply the same plain text the reader sees.
actions chooses the built-in controls and their display and keyboard order: copy, read, feedback, share. The default includes all four; duplicates are ignored. Add custom controls as children.
Each action composes a subtle icon Button. Muted text turns to ink on hover while the surface stays transparent.
The combined feedback icon opens helpful and unhelpful choices. Selecting the checked choice again clears it.
Use onFeedback to persist positive, negative, or cleared feedback. A rejected promise keeps the previous selection available for retry.
Use feedback for controlled selection or defaultFeedback for an initial local selection.
Supply onShare for an application-owned share flow. Otherwise the browser shares the text or copies it when native sharing is unavailable.
Read aloud uses browser speech only after activation. onReadingChange can coordinate an avatar with narration. Removing read stops owned narration; removing feedback closes its menu.
CSS-only markup supplies named controls; clipboard, speech, the feedback menu, and sharing require React or application code.
Avoid
Adding copyText to the same Response, which would duplicate its copy control.
Assuming local feedback has been stored on a server without supplying onFeedback.
Passing raw markup as text or automatically starting narration when a message appears.
Install
React package
npm install @noorddev/vlak-react
Load the stylesheet once at your app root, then import the components you use.
import "@noorddev/vlak-react/css";
import { Response, ResponseActions, type ResponseAction, type ResponseFeedback } from "@noorddev/vlak-react";
Per-component imports are available at @noorddev/vlak-react/components/response-actions.
Copy the source
npx @noorddev/vlak-cli add response-actions
Adds the component and its dependencies to components/vlak/. Follow the StyleX setup to compile the source in your application.
"use client";
import { useState } from "react";
import { Response, ResponseActions, type ResponseAction, type ResponseFeedback } from "@noorddev/vlak-react";
const controls: readonly ResponseAction[] = ["copy", "read", "feedback", "share"];
export function AnswerActions() {
const [feedback, setFeedback] = useState<ResponseFeedback>(null);
const answer = "The brief now names one owner and one next step.";
return <Response actions={<ResponseActions text={answer} actions={controls} feedback={feedback} onFeedback={setFeedback} />}>
<p>{answer}</p>
</Response>;
}
See the integration example to compose these components with your application's model and data.
Props
ResponseActions
Compact message actions. Speech and sharing run only after a button activation.
Prop
Type
Default
Description
textrequired
string
Plain text used for copying, narration, and the default share action.
actions
readonly ResponseAction[]
["copy", "read", "feedback", "share"]
Built-in controls in display and keyboard order. Omit for all four; duplicates are ignored.
feedback
ResponseFeedback
defaultFeedback
ResponseFeedback
null
onFeedback
(value: ResponseFeedback) => void | Promise<void>
A rejected promise preserves the previous selection and allows retry.
onShare
() => void | Promise<void>
Overrides native sharing. Without it, unsupported browsers copy the text.
onReadingChange
(reading: boolean) => void
Reports this response's narration state for an avatar or other presentation.
Also accepts HTMLAttributes<HTMLDivElement>.
The ref reaches HTMLDivElement.
Keyboard
Keys
Does
Tab
Moves through the available copy, narration, feedback, and share controls
Enter, Space
Activates the focused action or feedback choice; choosing the checked feedback item again clears it
Arrow Down, Arrow Up
Opens feedback on the first or last choice, then moves between choices
Home, End
Moves to the first or last feedback choice
Escape
Closes the feedback menu and returns focus to its trigger
Tab
Closes the feedback menu and moves focus to the next action
Accessibility
Every icon button has a readable name and title, a 44px target, and a visible focus outline.
One Rate response trigger exposes its expanded menu state. Helpful and unhelpful menu choices expose aria-checked and remain mutually exclusive.
The menu moves focus between choices and returns focus on selection or Escape. Outside interaction dismisses it without stealing focus.
A polite, atomic status region announces completed actions and recoverable errors. Clipboard success is reported only after the write resolves.
Read aloud is disabled when browser speech is unavailable and becomes Stop reading while this response is narrated. Replacing the text or unmounting stops this component's narration.
Pending asynchronous actions prevent duplicate activation. The feedback trigger remains focusable with aria-disabled while saving. Replacing the response text closes its menu and invalidates stale results.
The group accepts native div attributes, children for extra actions, className, style, and a forwarded div ref.
Markup
The same styles are available as CSS. Native HTML provides the static presentation; React or application code supplies state updates and actions.