Packages
@anvia/react-ui: Usage Patterns
Common ways to compose @anvia/react-ui with @anvia/react.
Pair with @anvia/react
@anvia/react-ui expects controllers from @anvia/react.
- Use
useChat(...)withChatProvider,Thread,Message,Composer, andHumanInput. - Use
useCompletion(...)withCompletionProviderandCompletion. - Keep server routes, auth, persistence, and model selection outside the UI package.
React routes should accept the @anvia/react request shape { messages, stream: true }. See
React UI server routes for complete examples.
The shared request shape does not mean every primitive can read every provider. Thread,
Composer, Message, and HumanInput read chat context from ChatProvider. Completion.* reads
completion context from CompletionProvider.
Use as headless primitives
Every primitive supports className and stable data-anvia-* attributes. Button-like primitives also support asChild, so applications can attach behavior to design-system components.
<Composer.Submit asChild>
<button className="primary-action">Send</button>
</Composer.Submit>
Render Anvia agent parts
Message.Parts renders Anvia UIMessagePart values by default:
textreasoningtoolattachmentdataerror
For custom rendering, pass children to Message.Part or use useMessagePart().
Message.Tool also accepts a render function for merged tool-call input/result cards:
<Message.Parts>
{(part) =>
part.type === "tool" ? (
<Message.Part>
<Message.Tool>
{(tool) => (
<ToolCard name={tool.toolName} input={tool.input} output={tool.output} />
)}
</Message.Tool>
</Message.Part>
) : part.type === "attachment" ? (
<Message.Part>
<Message.Attachment />
</Message.Part>
) : (
<Message.Part />
)
}
</Message.Parts>
Tool rendering is not locked to one timing. Render immediately, only while pending, only when settled, or filter tool parts before wrappers are created:
<Message.Tool renderWhen="always" />
<Message.Tool renderWhen="pending" />
<Message.Tool renderWhen="settled" />
<Message.Parts
filter={(part) => part.type !== "tool" || part.state === "output-available"}
/>
renderWhen="pending" includes both provisional input-streaming parts created from
tool_call_delta events and completed input-available tool calls. This lets an application show a
“Preparing tool…” state as soon as the provider identifies the tool.
Human input
HumanInput.Approvals and HumanInput.Questions read useChat human-input state and call the
matching controller actions. They are meant for tool approval and question workflows emitted by
Anvia agents or Studio-compatible streams, so they belong in chat surfaces rather than completion
surfaces.
Application code owns the decision and answer routes. See Human review end to end.
Attachments and Markdown
Use Composer.Attachments, Composer.AttachmentInput, Composer.AddAttachment, and
Composer.AttachmentDropzone for pending file attachments. Composer.Input auto-resizes from
minRows to maxRows rows, with maxRows defaulting to 6.
Keep Composer.Root uncontrolled for simple chat surfaces. Use input, onInputChange,
attachments, and onAttachmentsChange when the draft or pending attachments need to sync with
application state.
<Composer.Root
input={draft}
onInputChange={setDraft}
attachments={attachments}
onAttachmentsChange={setAttachments}
>
<Composer.Attachments keepMounted />
<Composer.AttachmentInput multiple />
<Composer.Input />
<Composer.Submit />
</Composer.Root>
Use Message.Markdown when text parts should render GitHub-flavored Markdown; pass components to
replace code blocks or other Markdown elements with app-owned components.
For a streaming mixed-part response, put the lifecycle on Message.Parts so tool cards remain
behind buffered text:
<Message.Parts
stream={{
isStreaming: chat.status === "streaming" && chat.messages.at(-1)?.id === message.id,
resetKey: message.id,
flushImmediately: chat.status === "error",
}}
>
{(part) => (part.type === "text" ? <Message.Markdown /> : <Message.Part />)}
</Message.Parts>
Keep the lifecycle present with isStreaming: false at completion to allow the buffered tail to
drain. Change resetKey when the displayed conversation changes.
Completion panels
Use Completion.Root, Completion.Output, Completion.Form, Completion.Input,
Completion.Stop, and Completion.Submit for prompt-to-text panels. Do not add Thread,
Composer, Message, or HumanInput inside CompletionProvider; move to a chat surface when the
product needs those primitives.
