Skip to main content

React Components

Streaming-ready UI components for building AI-powered chat interfaces.

npm install @ainative/ai-kit

Requires: React 18+


StreamingMessage​

Renders an AI message with real-time streaming animations and Markdown support. Designed to be used with useChat and updated in-place as tokens arrive.

Usage​

import { StreamingMessage } from '@ainative/ai-kit';

export function MessageBubble() {
return (
<StreamingMessage
role="assistant"
content="Here is a Python example:\n\n```python\nprint('hello')\n```"
streamingState="streaming"
animationType="smooth"
enableMarkdown={true}
codeTheme="vs-dark"
/>
);
}

Props​

NameTypeDefaultDescription
role'user' | 'assistant' | 'system'requiredMessage role — controls layout and visual styling
contentstringrequiredMessage text. Supports GitHub Flavored Markdown when enableMarkdown is true
streamingState'idle' | 'streaming' | 'done''idle'Drives animation behavior. Set to 'streaming' while tokens are arriving, then 'done'
animationType'none' | 'fade' | 'typewriter' | 'smooth''typewriter'How new content is animated in
enableMarkdownbooleantrueRender content as GitHub Flavored Markdown
codeTheme'dark' | 'light' | 'vs-dark' | 'github' | 'monokai' | 'nord' | 'dracula''vs-dark'Syntax highlighting theme applied to fenced code blocks inside the message

Animation types​

ValueBehavior
noneContent appears immediately with no animation
fadeNew tokens fade in
typewriterTokens render character by character (classic typewriter effect)
smoothTokens stream in with a smooth sliding transition

Code theme options​

ValueDescription
darkDark background, high contrast
lightLight background — use on white/grey surfaces
vs-darkVisual Studio Code dark (default)
githubGitHub-style monochrome
monokaiMonokai classic dark
nordNord arctic color palette
draculaDracula purple-dark theme

Full chat example​

import { useState } from 'react';
import { StreamingMessage, StreamingIndicator } from '@ainative/ai-kit';
import { AINativeProvider, useChat } from '@ainative/react-sdk';
import type { Message } from '@ainative/react-sdk';

function Chat() {
const { messages, sendMessage, isLoading } = useChat({
model: 'meta-llama/llama-3.3-70b-instruct',
temperature: 0.7,
});
const [input, setInput] = useState('');

const handleSubmit = async () => {
if (!input.trim()) return;
const next: Message[] = [
...messages,
{ role: 'user', content: input },
];
setInput('');
await sendMessage(next);
};

return (
<div className="flex flex-col gap-4 p-4">
{messages.map((msg, i) => (
<StreamingMessage
key={i}
role={msg.role}
content={msg.content}
streamingState="done"
animationType="smooth"
codeTheme="vs-dark"
/>
))}

{isLoading && <StreamingIndicator variant="dots" size="md" />}

<div className="flex gap-2">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSubmit()}
placeholder="Type a message…"
className="flex-1 px-3 py-2 rounded border"
/>
<button onClick={handleSubmit} disabled={isLoading}>
Send
</button>
</div>
</div>
);
}

export function App() {
return (
<AINativeProvider config={{ apiKey: process.env.NEXT_PUBLIC_AINATIVE_API_KEY! }}>
<Chat />
</AINativeProvider>
);
}

Accessibility​

  • Rendered output uses semantic HTML (<article>, <p>, <code>, <pre>)
  • Respects prefers-reduced-motion — animations are disabled for users who opt out
  • Code blocks include role="region" and a visually hidden label for screen readers

CodeBlock​

Syntax-highlighted code display with an optional copy button and line numbers. Used internally by StreamingMessage for fenced code blocks; also available standalone.

Usage​

import { CodeBlock } from '@ainative/ai-kit';

export function Example() {
return (
<CodeBlock
code={`import zerodb from 'zerodb'

const db = await zerodb.connect({ project: 'my-project' })
const results = await db.search('find documents about AI')
console.log(results)`}
language="typescript"
showLineNumbers={true}
showCopyButton={true}
theme="vs-dark"
filename="search.ts"
/>
);
}

Props​

NameTypeDefaultDescription
codestringrequiredSource code string to display
languagestring'text'Language identifier for syntax highlighting (e.g. 'typescript', 'python', 'bash')
theme'dark' | 'light' | 'vs-dark' | 'github' | 'monokai' | 'nord' | 'dracula''vs-dark'Syntax highlighting theme
showLineNumbersbooleanfalseDisplay line numbers in the gutter
showCopyButtonbooleantrueRender a copy-to-clipboard button in the top-right corner
filenamestring—Optional filename shown in a tab above the code block

Supported languages​

Any language identifier supported by the underlying syntax highlighter is accepted. Common values include: typescript, javascript, python, bash, json, yaml, sql, go, rust, html, css, markdown.

Standalone example​

import { CodeBlock } from '@ainative/ai-kit';

const snippet = `
from zerodb import ZeroDB

client = ZeroDB(api_key="your-key")
results = client.search(query="semantic search", top_k=5)
`.trim();

export function PythonExample() {
return (
<CodeBlock
code={snippet}
language="python"
theme="monokai"
showLineNumbers={true}
filename="example.py"
/>
);
}

Accessibility​

  • Code block container has role="region" with a descriptive aria-label
  • Copy button includes aria-label="Copy code" and announces success via aria-live
  • Line numbers are aria-hidden so screen readers read the code without number noise

StreamingIndicator​

Animated loading indicator displayed while an AI response is being generated. Render this alongside your message list whenever isLoading is true.

Usage​

import { StreamingIndicator } from '@ainative/ai-kit';

// Minimal usage
<StreamingIndicator />

// With all props
<StreamingIndicator
variant="dots"
size="md"
color="#6366f1"
/>

Props​

NameTypeDefaultDescription
variant'dots' | 'pulse' | 'wave''dots'Visual animation style
size'sm' | 'md' | 'lg''md'Size of the indicator
colorstring—CSS color value applied to the indicator elements. Falls back to the current text color

Variant descriptions​

ValueDescription
dotsThree bouncing dots — classic chat "typing" indicator
pulseA single element pulsing in and out
waveMultiple bars animating up and down in a wave pattern

Conditional rendering example​

import { StreamingMessage, StreamingIndicator } from '@ainative/ai-kit';
import { useChat } from '@ainative/react-sdk';
import type { Message } from '@ainative/react-sdk';

export function ChatFeed() {
const { messages, sendMessage, isLoading } = useChat({
model: 'meta-llama/llama-3.3-70b-instruct',
});

return (
<div>
{messages.map((msg, i) => (
<StreamingMessage
key={i}
role={msg.role}
content={msg.content}
streamingState="done"
/>
))}

{isLoading && (
<div className="flex items-center gap-2 py-2 text-gray-500">
<StreamingIndicator variant="dots" size="sm" />
<span className="text-sm">Thinking…</span>
</div>
)}
</div>
);
}

Accessibility​

  • The indicator element has role="status" and aria-label="Loading response"
  • Animations are suppressed when prefers-reduced-motion: reduce is set
  • The component renders nothing when not needed — avoid conditional wrappers that leave an empty <div> in the DOM

TypeScript types​

import type {
// From @ainative/ai-kit
StreamingMessageProps,
CodeBlockProps,
StreamingIndicatorProps,
} from '@ainative/ai-kit';

// Core message and config types from @ainative/react-sdk
import type {
Message,
AINativeConfig,
AINativeError,
ChatCompletionResponse,
CreditBalance,
Usage,
} from '@ainative/react-sdk';

See the source repository for full type definitions.