Skip to main content

React Quickstart

Five minutes from clone to working chat in React. Install, seed, wire the provider, drop in the library and chat components. Done.

1. Install

bash
npm install @cstar.help/react

2. Seed sample data

Empty workspaces aren't fun to test against. Populate yours with realistic content first:

bash
cstar seed

Creates 5 categories, 12 articles, 3 customers, and 5 tickets. Full breakdown over at the quickstart.

3. Wire up the providers

providers.tsx
// app/providers.tsx
// Two providers: Chat (authenticated) and Library (public)
import { CStarChatProvider, CStarLibraryProvider } from '@cstar.help/react';

export default function Providers({ children }) {
  return (
    <CStarLibraryProvider teamSlug="acme">
      <CStarChatProvider teamSlug="acme">
        {children}
      </CStarChatProvider>
    </CStarLibraryProvider>
  );
}

4. Browse the Knowledge Base

List categories and articles from your public help center.

HelpCenter.tsx
// components/HelpCenter.tsx
import { useCategories, useArticles } from '@cstar.help/react';

export function HelpCenter() {
  const { categories, isLoading } = useCategories();
  const { articles } = useArticles({ limit: 5 });

  if (isLoading) return <p>Loading...</p>;

  return (
    <div>
      <h2>Help Center</h2>
      {categories.map(cat => (
        <div key={cat.id}>
          <h3>{cat.name} ({cat.article_count})</h3>
        </div>
      ))}
      <h2>Latest Articles</h2>
      {articles.map(a => (
        <a key={a.id} href={`/help/${a.slug}`}>{a.title}</a>
      ))}
    </div>
  );
}

5. Add Customer Chat

Let customers open tickets and send messages in real-time.

ChatWidget.tsx
// components/ChatWidget.tsx
import { useChat, useTickets, useMessages } from '@cstar.help/react';
import { useState } from 'react';

export function ChatWidget() {
  const { identify, isIdentified } = useChat();
  const { tickets, create } = useTickets();
  const [activeId, setActiveId] = useState(null);
  const { messages, send } = useMessages(activeId);
  const [draft, setDraft] = useState('');

  async function startChat() {
    // Get HMAC signature from your server
    const res = await fetch('/api/cstar-auth');
    const { signature, customer } = await res.json();
    await identify(customer, signature);

    const ticket = await create({ title: 'Help needed' });
    setActiveId(ticket.id);
  }

  if (!isIdentified) {
    return <button onClick={startChat}>Chat with us</button>;
  }

  return (
    <div>
      {messages.map(m => (
        <p key={m.id}><b>{m.sender_name}</b>: {m.content}</p>
      ))}
      <input value={draft} onChange={e => setDraft(e.target.value)} />
      <button onClick={() => { send(draft); setDraft(''); }}>Send</button>
    </div>
  );
}

Full-text article search with built-in debounce.

SearchBar.tsx
// components/SearchBar.tsx
import { useArticleSearch } from '@cstar.help/react';
import { useState } from 'react';

export function SearchBar() {
  const [query, setQuery] = useState('');
  const { results, totalCount, isLoading } = useArticleSearch(query);

  return (
    <div>
      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="Search help articles..."
      />
      {isLoading ? <p>Searching...</p> : <p>{totalCount} results</p>}
      {results.map(a => (
        <a key={a.id} href={`/help/${a.slug}`}>{a.title}</a>
      ))}
    </div>
  );
}

What's Next?