One message in a conversation with an AI assistant, with a cursor while it streams and Copy, Regenerate and feedback under it.
$ pnpm dlx shadcn@latest add https://dashral.com/r/message.jsonInstallation
$ pnpm dlx shadcn@latest add https://dashral.com/r/message.jsonAdds the component, the components it builds on, its npm packages and the theme tokens it uses. Using Dashral often? Add the registry to components.json once:
{
"registries": {
"@dashral": "https://dashral.com/r/{name}.json"
}
}Then add components by name:
$ pnpm dlx shadcn@latest add @dashral/messageUsage
import { Message } from "@/components/dashral/message"
<Message
from="assistant"
onRegenerate={() => api.chat.regenerate()}
onFeedbackChange={(feedback) => api.chat.feedback(feedback)}
>
Revenue rose 12% this month, led by the Team plan.
</Message>Examples
API reference
Message
Also takes every prop of <article>(opens in a new tab).
| Prop | Type | Default |
|---|---|---|
from | "user" | "assistant"Required. Yours sit at the end in a bubble; the assistant's open flat beside its avatar. | — |
children | ReactNodeText (line breaks kept) or your own rendering: Markdown, a table, a chart. | — |
name | stringThe sender, for the avatar's initials and screen readers. | "You" / "Assistant" |
avatar | string | ReactNode | falseAn image URL or your own mark. The assistant shows a sparkle by default, you nothing; false hides it. | — |
time | Date | stringA Date is written in the locale; a string as given ("2 min ago"). | — |
status | "streaming" | "done" | "error"Streaming shows a cursor and holds the actions back; error says so. | "done" |
copyText | stringWhat Copy copies; the text as it reads on screen by default. | — |
onRegenerate | () => voidShows Regenerate, and Try again after an error. | — |
feedback / defaultFeedback | "up" | "down" | nullGood or bad response, controlled or initial. | null |
onFeedbackChange | (feedback) => voidShows the two feedback buttons. Pressing the chosen one again clears it. | — |
actions | ReactNodeMore buttons, after the built-in ones. | — |
showActions | "hover" | "always" | falseHover shows them with the pointer or focus on the message, and always on touch screens. | "hover" |
error | ReactNodeWhat an error says. | "Couldn't finish this answer." |
classNames | { content?, avatar?, actions?, meta? }Classes for each part. | — |
className | stringExtra classes, merged with cn() so yours win. | — |
Accessibility
- Each message is an article named by its sender; put them in an element with role="log" (Conversation does) so new ones are announced.
- While it streams, aria-busy holds screen readers back until the answer is whole, instead of reading every word.
- The action buttons are named (Copy, Regenerate, Good response, Bad response) with tooltips; the feedback buttons say which one is pressed.
- Hover-only actions still show on keyboard focus, and always on touch screens.
- dir="auto" on the text, so an answer in Arabic reads right to left in an English app.
Motion
- The streaming cursor pulses, and stands still with reduced motion. The actions fade in over --duration-fast.