Skip to main content

React SDK

Add AI chat and search to your React application with @groo.dev/ai-react.

Installation

npm install @groo.dev/ai-react

Quick Start

Wrap your app with AIProvider and use the components:

import { AIProvider, GrooChat } from '@groo.dev/ai-react'

function App() {
return (
<AIProvider
projectId="your-project-id"
auth={{
accountsUrl: 'https://accounts.groo.dev',
clientId: 'your-client-id',
}}
>
<GrooChat />
</AIProvider>
)
}

AIProvider

The AIProvider component wraps your app and provides authentication and AI client context.

Props

PropTypeRequiredDescription
projectIdstringYesYour Groo AI project ID
auth.accountsUrlstringYesGroo accounts URL
auth.clientIdstringYesYour OAuth client ID
apiUrlstringNoCustom API URL (default: https://ai.groo.dev)
queryClientQueryClientNoCustom React Query client

Example

import { AIProvider } from '@groo.dev/ai-react'

function App() {
return (
<AIProvider
projectId="proj_abc123"
apiUrl="https://ai.groo.dev"
auth={{
accountsUrl: 'https://accounts.groo.dev',
clientId: 'client_xyz',
}}
>
{children}
</AIProvider>
)
}

Components

GrooChat

A drop-in chat component with markdown rendering and streaming responses.

import { GrooChat } from '@groo.dev/ai-react'

function ChatPage() {
return <GrooChat />
}

Props

PropTypeDefaultDescription
placeholderstring'Ask a question...'Input placeholder text
welcomeMessagestring'How can I help you today?'Message shown when chat is empty

Features

  • Auto-scrolling message list
  • Expandable textarea (auto-resize)
  • Markdown rendering for responses
  • Send/stop button toggle
  • "New chat" option menu
  • Error display

A search component for finding documentation.

import { Search } from '@groo.dev/ai-react'

function SearchPage() {
return <Search onResultClick={(url) => window.location.href = url} />
}

Props

PropTypeDefaultDescription
placeholderstring'Search documentation...'Input placeholder
limitnumber10Max results to return
onResultClick(url: string) => voidOpens in new tabResult click handler

Hooks

useChat

Build a custom chat UI with the useChat hook.

import { useChat } from '@groo.dev/ai-react'

function CustomChat() {
const { messages, isLoading, sendMessage, reset, stop } = useChat()

return (
<div>
{messages.map((msg, i) => (
<div key={i} className={msg.role}>
{msg.content}
</div>
))}

<input
onKeyDown={(e) => {
if (e.key === 'Enter') {
sendMessage(e.currentTarget.value)
e.currentTarget.value = ''
}
}}
disabled={isLoading}
/>

{isLoading && <button onClick={stop}>Stop</button>}
<button onClick={reset}>New Chat</button>
</div>
)
}

Return Value

interface UseChatResult {
messages: Message[]
isLoading: boolean
isError: boolean
error: Error | null
sendMessage: (content: string) => void
reset: () => void
stop: () => void
}

interface Message {
role: 'user' | 'assistant'
content: string
}

useSearch

Search your indexed documentation.

import { useSearch } from '@groo.dev/ai-react'

function CustomSearch() {
const [query, setQuery] = useState('')
const { results, isLoading, isError } = useSearch(query, { limit: 5 })

return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>

{isLoading && <div>Searching...</div>}

{results.map((result, i) => (
<a key={i} href={result.url}>
<h3>{result.title}</h3>
<p>{result.snippet}</p>
</a>
))}
</div>
)
}

Parameters

ParameterTypeDescription
querystringSearch query
options.limitnumberMax results (default: 10)

Return Value

interface UseSearchResult {
results: SearchResult[]
isLoading: boolean
isError: boolean
error: Error | null
}

interface SearchResult {
title: string
url: string
snippet: string
score: number
}

useAuth

Access authentication state.

import { useAuth } from '@groo.dev/ai-react'

function AuthStatus() {
const { user, isLoading, login, logout } = useAuth()

if (isLoading) return <div>Loading...</div>

if (!user) {
return <button onClick={login}>Sign in</button>
}

return (
<div>
Welcome, {user.name}
<button onClick={logout}>Sign out</button>
</div>
)
}

useAI

Access the underlying Groo client for advanced use cases.

import { useAI } from '@groo.dev/ai-react'

function Advanced() {
const { client, projectId } = useAI()

// Use the OpenAI-compatible client directly
const handleStream = async () => {
const stream = await client.chat.chat.completions.create({
model: 'anthropic/claude-sonnet-4-20250514',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true,
})

for await (const chunk of stream) {
console.log(chunk.choices[0]?.delta?.content)
}
}

return <button onClick={handleStream}>Stream</button>
}

Styling

Components use CSS classes you can customize:

/* Chat container */
.groo-chat { }
.groo-chat-messages { }
.groo-chat-message { }
.groo-chat-message-user { }
.groo-chat-message-assistant { }
.groo-chat-input-wrapper { }
.groo-chat-textarea { }
.groo-chat-button { }
.groo-chat-welcome { }
.groo-chat-error { }

/* Search container */
.groo-search { }
.groo-search-form { }
.groo-search-input { }
.groo-search-button { }
.groo-search-results { }
.groo-search-result { }
.groo-search-result-title { }
.groo-search-result-snippet { }

TypeScript

All types are exported:

import type {
AIProviderProps,
GrooChatProps,
SearchProps,
UseChatResult,
UseSearchResult,
Message,
SearchResult,
} from '@groo.dev/ai-react'

Next.js

For Next.js apps, ensure components run on the client:

'use client'

import { AIProvider, GrooChat } from '@groo.dev/ai-react'

export function DocsChat() {
return (
<AIProvider
projectId={process.env.NEXT_PUBLIC_GROO_PROJECT_ID!}
auth={{
accountsUrl: 'https://accounts.groo.dev',
clientId: process.env.NEXT_PUBLIC_GROO_CLIENT_ID!,
}}
>
<GrooChat />
</AIProvider>
)
}