Our React SDK provides a powerful set of hooks and components to build custom chat interfaces while leveraging our chat infrastructure.

Installation

npm install @opencx/widget

Quick Setup

Wrap your app with our WidgetRoot provider:

import { WidgetRoot } from '@opencx/widget/react';

function App() {
  return (
    <WidgetRoot
      config={{
        token: 'YOUR_BOT_TOKEN',
        apiUrl: 'YOUR_API_URL',
        initialMessages: ['How can I help you today?'],
        user: {
          email: "user@example.com",
          name: "User Name"
        },
        bot: {
          name: "AI Assistant",
          avatarUrl: "/bot-avatar.png"
        }
      }}
    >
      <YourCustomChat />
    </WidgetRoot>
  );
}

Configuration Options

interface WidgetConfig {
  // Required
  token: string;                // Your bot authentication token

  // Network
  apiUrl?: string;             // Custom API URL
  socketUrl?: string;          // Custom WebSocket URL
  headers?: Record<string, string>; // Custom headers

  // Initial Setup
  initialMessages?: string[];  // Welcome messages
  defaultOpen?: boolean;       // Open chat by default
  debug?: boolean;            // Enable debug mode

  // User Configuration
  user?: {
    name?: string;
    email?: string;
    phone?: string;
    avatarUrl?: string;
    customData?: Record<string, string>;
  };

  // Bot Configuration
  bot?: {
    name?: string;
    avatarUrl?: string;
    description?: string;
  };

  // Behavior
  settings?: {
    persistSession?: boolean;  // Keep chat history
    useSoundEffects?: boolean; // Enable sounds
    enableTypingIndicator?: boolean;
    messageDelay?: number;    // Delay between messages
  };

  // Callbacks
  onClose?: () => void;
  onOpen?: () => void;
  onMessage?: (message: MessageType) => void;
  onError?: (error: Error) => void;
}

Available Hooks

useChat

The main hook for chat functionality:

function ChatInterface() {
  const {
    messages,         // Array of chat messages
    sendMessage,      // Send a new message
    loading,          // Loading state
    error,           // Error state
    clearChat,       // Clear chat history
    restartChat      // Start a new session
  } = useChat();

  return (
    <div className="chat-interface">
      <MessageList messages={messages} />
      <InputArea onSend={sendMessage} disabled={loading} />
      {error && <ErrorMessage error={error} />}
    </div>
  );
}

useConfig

Access and update configuration:

function ChatSettings() {
  const { config, updateConfig } = useConfig();

  const toggleSound = () => {
    updateConfig({
      settings: {
        ...config.settings,
        useSoundEffects: !config.settings?.useSoundEffects
      }
    });
  };

  return (
    <button onClick={toggleSound}>
      {config.settings?.useSoundEffects ? 'Mute' : 'Unmute'}
    </button>
  );
}

useLocale

Handle internationalization:

function LanguageSelector() {
  const { locale, setLocale, t } = useLocale();

  return (
    <select 
      value={locale} 
      onChange={(e) => setLocale(e.target.value)}
      aria-label={t('selectLanguage')}
    >
      <option value="en">English</option>
      <option value="es">Español</option>
      <option value="fr">Français</option>
    </select>
  );
}

useFeedback

Handle message feedback:

function MessageFeedback({ messageId }: { messageId: string }) {
  const { submitFeedback, loading } = useFeedback(messageId);

  return (
    <div className="feedback-buttons">
      <button
        onClick={() => submitFeedback('helpful')}
        disabled={loading}
        aria-label="Mark as helpful"
      >
        👍
      </button>
      <button
        onClick={() => submitFeedback('not_helpful')}
        disabled={loading}
        aria-label="Mark as not helpful"
      >
        👎
      </button>
    </div>
  );
}

Building Custom Components

Message Components

Create custom message displays:

function CustomMessage({ message }: { message: MessageType }) {
  // Handle different message types
  if (message.type === 'FROM_BOT' && message.data.type === 'weather') {
    return <WeatherCard data={message.data} />;
  }

  return (
    <div className={`message ${message.type.toLowerCase()}`}>
      {message.content}
    </div>
  );
}

function WeatherCard({ data }: { data: WeatherData }) {
  return (
    <div className="weather-card">
      <h3>{data.location}</h3>
      <p>{data.temperature}°C</p>
      <p>{data.description}</p>
    </div>
  );
}

Input Components

Create custom input interfaces:

function VoiceInput() {
  const { sendMessage } = useChat();
  const [recording, setRecording] = useState(false);

  const handleVoiceInput = async () => {
    try {
      const transcript = await startVoiceRecording();
      await sendMessage(transcript);
    } catch (error) {
      console.error('Voice input failed:', error);
    }
  };

  return (
    <button
      onClick={handleVoiceInput}
      className={recording ? 'recording' : ''}
      aria-label={recording ? 'Stop recording' : 'Start recording'}
    >
      🎤
    </button>
  );
}

Best Practices

  1. State Management

    • Use hooks for managing local state
    • Implement proper cleanup
    • Handle loading and error states
  2. Performance

    • Memoize callbacks and computations
    • Use virtualization for long lists
    • Implement proper error boundaries
  3. Accessibility

    • Add ARIA labels and roles
    • Support keyboard navigation
    • Handle screen readers
  4. User Experience

    • Show loading states
    • Provide clear error messages
    • Add animations and transitions
  5. Testing

    • Test all user interactions
    • Mock API responses
    • Test error scenarios

Need help? Check our example repo or join our Discord community.