npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@traiyani/chatsdk-react

v1.0.14

Published

ChatSDK React SDK - Pre-built, plug-and-play real-time chat components for React

Readme

ChatSDK React SDK

React SDK for ChatSDK - Real-time chat solution with product-based conversations, Socket.IO, instant messaging, and file sharing. Fully isolated and self-contained.

Features

  • Zero boilerplate — 3 steps: wrap with provider, login, use <ChatPanel />
  • Fully isolated — all dependencies bundled, no global side effects, scoped CSS
  • React 16.8+ (hooks)
  • Real-time messaging via Socket.IO
  • Product-based conversations with metadata
  • File/image/video uploads and sharing
  • Block/unblock users
  • Internationalization (English + Arabic with RTL)
  • Dark mode support (light / dark / auto)
  • Typing indicators, read receipts, unread counts
  • CSS auto-injection — no manual stylesheet import required

Table of Contents

  1. Installation
  2. SDK Initialization (Provider)
  3. User Authentication
  4. ChatPanel Component
  5. ChatPanel Props Reference
  6. Ref Methods
  7. Theme Support
  8. Internationalization (i18n)
  9. TypeScript Support
  10. Troubleshooting

1. Installation

npm install @traiyani/chatsdk-react

That's it. axios and socket.io-client are peer dependencies — install them if your project doesn't have them already:

npm install axios socket.io-client

| Dependency | Minimum Version | |---|---| | react | >= 16.8.0 | | react-dom | >= 16.8.0 | | axios | >= 0.21.0 | | socket.io-client | >= 4.0.0 |

Works with Vite, webpack, Next.js, Create React App, Parcel, and any React bundler out of the box.

CSS (Auto-Injected)

CSS is automatically injected when you import any SDK export. No manual stylesheet import is needed.

import { ChatPanel } from '@traiyani/chatsdk-react';

All SDK styles are scoped under .chatsdk-root so they never conflict with your app's CSS (Bootstrap, Tailwind, etc.).

If you prefer to import the stylesheet manually (e.g., for SSR or custom loading order):

import '@traiyani/chatsdk-react/dist/chatsdk.css';

Optional: Load Fonts

The SDK UI uses Mulish and Lato fonts. If your app doesn't already load them, add this to your HTML <head>:

<link href="https://fonts.googleapis.com/css2?family=Mulish:wght@400;500;600;700&family=Lato:wght@400;700&display=swap" rel="stylesheet">

2. SDK Initialization

Wrap your app (or the chat-using subtree) with <ChatSDKProvider>. This initializes the singleton SDK instance and makes it available to all child components.

// index.tsx or App.tsx
import { ChatSDKProvider } from '@traiyani/chatsdk-react';

const sdkConfig = {
  apiBaseUrl: 'https://your-chat-api.com/api',
  appId: 'your-app-id',
  environment: 'production' as const,
};

function Root() {
  return (
    <ChatSDKProvider config={sdkConfig}>
      <App />
    </ChatSDKProvider>
  );
}

Configuration Options

| Option | Type | Required | Default | Description | |---|---|---|---|---| | apiBaseUrl | string | Yes | — | Chat API server URL | | appId | string | Yes | — | Your application ID | | environment | 'development' \| 'staging' \| 'production' | Yes | — | Environment | | enableLogging | boolean | No | false | Enable debug logging in console | | autoConnect | boolean | No | true | Auto-connect WebSocket after auth | | timeout | number | No | 30000 | HTTP request timeout in ms |

Environment Variables

Config values can come from any source:

// Create React App
const sdkConfig = {
  apiBaseUrl: process.env.REACT_APP_API_URL,
  appId: process.env.REACT_APP_APP_ID,
  environment: process.env.REACT_APP_ENV,
};

// Vite
const sdkConfig = {
  apiBaseUrl: import.meta.env.VITE_API_URL,
  appId: import.meta.env.VITE_APP_ID,
  environment: import.meta.env.VITE_ENVIRONMENT,
};

// Next.js
const sdkConfig = {
  apiBaseUrl: process.env.NEXT_PUBLIC_API_URL,
  appId: process.env.NEXT_PUBLIC_APP_ID,
  environment: process.env.NEXT_PUBLIC_ENV,
};

3. User Authentication

Use the useChatSDK() hook to login, verify users, and logout. These are the only auth calls your website needs to make.

3.1 Login the Current User

Call login() once after the website user authenticates (e.g., after website login). This saves the chat token and connects the WebSocket.

import { useChatSDK } from '@traiyani/chatsdk-react';

function AfterLogin() {
  const { login } = useChatSDK();

  const handleWebsiteLogin = async (websiteUser) => {
    // ... your website login logic ...

    // Then login to chat:
    const chatUser = await login({
      id: websiteUser.id,       // Your app's user ID
      name: websiteUser.name,   // Display name
      email: websiteUser.email, // Email
    });

    console.log('Chat user logged in:', chatUser.name);
  };

  return <button onClick={() => handleWebsiteLogin(myUser)}>Login</button>;
}

What happens internally:

  1. Authenticates the user with the chat server (login or auto-register)
  2. Saves the auth token to localStorage
  3. Connects the WebSocket for real-time messaging

3.2 Verify Another User

Call verifyUser() to check if another user (e.g., a seller) exists in the chat system, or register them if they don't. This does NOT save a token or connect a socket — it's purely a lookup.

const { verifyUser } = useChatSDK();

const otherUser = await verifyUser({
  id: 'seller-456',
  name: 'Mohammed',
  email: '[email protected]',
});

console.log('Verified:', otherUser.name, otherUser.id);

3.3 Logout

Call logout() when the website user logs out. This disconnects the socket, clears the token, and cleans up all state.

const { logout } = useChatSDK();

await logout();

3.4 Reactive State

The hook exposes shared state across all components:

const { currentUser, isInitialized, isConnected } = useChatSDK();

// In JSX:
// {currentUser?.name}
// {isConnected ? 'Online' : 'Offline'}

4. ChatPanel Component

<ChatPanel /> is the main UI component. It handles everything internally: conversation layout, socket rooms, real-time events, language switching, and error containment.

4.1 Open a Direct Chat (mode = "chat")

Opens a chat popup with a specific user, optionally about a product.

import { useState } from 'react';
import { ChatPanel } from '@traiyani/chatsdk-react';

function ProductPage() {
  const [showChat, setShowChat] = useState(false);

  const product = {
    id: 'CAR_123',
    ownerId: 'seller-456',
    name: 'Toyota Camry 2023',
    image: 'https://example.com/car.jpg',
    price: 25000,
    category: 'Vehicles',
  };

  return (
    <div>
      <h1>{product.name}</h1>
      <button onClick={() => setShowChat(true)}>Chat with Seller</button>

      <ChatPanel
        visible={showChat}
        onVisibleChange={setShowChat}
        mode="chat"
        targetUser={{ id: product.ownerId }}
        product={{
          productId: product.id,
          productName: product.name,
          productImage: product.image,
          price: product.price,
          currency: 'QAR',
          category: product.category,
        }}
        chatMetadata={{ source: 'product-page', adType: 'featured' }}
        locale="en"
      />
    </div>
  );
}

4.2 Open Conversation List (mode = "conversations")

Opens a panel with the conversation list sidebar and chat window.

import { useState, useRef } from 'react';
import { ChatPanel } from '@traiyani/chatsdk-react';
import type { ChatPanelRef } from '@traiyani/chatsdk-react';

function Navbar() {
  const [showMessages, setShowMessages] = useState(false);
  const [unread, setUnread] = useState(0);
  const chatPanelRef = useRef<ChatPanelRef>(null);

  return (
    <nav>
      <button onClick={() => setShowMessages(true)}>
        Messages
        {unread > 0 && <span className="badge">{unread}</span>}
      </button>

      <ChatPanel
        ref={chatPanelRef}
        visible={showMessages}
        onVisibleChange={setShowMessages}
        mode="conversations"
        locale="en"
        onUnreadCountChange={(count) => setUnread(count)}
      />
    </nav>
  );
}

4.3 Chat with a User by Name + Email (No ID)

When you don't have the other user's external ID, pass their name and email. The SDK will authenticate/register them automatically.

<ChatPanel
  visible={showChat}
  onVisibleChange={setShowChat}
  mode="chat"
  targetUser={{ name: 'Ahmed', email: '[email protected]' }}
  product={{ productId: '456', productName: 'Phone', productImage: 'https://...' }}
  chatMetadata={{ source: 'user-profile' }}
  locale="en"
/>

4.4 Target User Resolution Logic

| What you pass | SDK behavior | |---|---| | { id: 'ext-123' } | Uses ID directly, skips user verification | | { id: 'ext-123', name: 'Ahmed', email: '...' } | Uses ID directly, skips verification | | { name: 'Ahmed', email: '[email protected]' } | Authenticates/registers user by name + email, then uses returned ID | | { email: '[email protected]', phone: '+974...' } | Authenticates by email, phone stored as metadata |

Rule: If targetUser.id is present, the SDK skips verification. Otherwise, it authenticates the user first.

4.5 ExternalGroupId

The externalGroupId is a unique identifier for a conversation between two users (optionally about a product). It prevents duplicate conversations.

  • If you provide externalGroupId — the SDK uses it as-is.
  • If you omit it — the SDK generates one automatically using SHA-256 hash of the sorted user IDs + product ID.
{/* SDK generates groupId automatically */}
<ChatPanel
  visible={showChat}
  onVisibleChange={setShowChat}
  mode="chat"
  targetUser={{ id: 'seller-456' }}
  product={{ productId: 'CAR_123', productName: 'Car', productImage: '...' }}
/>

{/* You provide your own groupId */}
<ChatPanel
  visible={showChat}
  onVisibleChange={setShowChat}
  mode="chat"
  targetUser={{ id: 'seller-456' }}
  product={{ productId: 'CAR_123', productName: 'Car', productImage: '...' }}
  externalGroupId={myCustomGroupId}
/>

4.6 Complete Integration Example

Full working example — from install to running chat:

index.tsx:

import { ChatSDKProvider } from '@traiyani/chatsdk-react';

const sdkConfig = {
  apiBaseUrl: process.env.REACT_APP_API_URL,
  appId: process.env.REACT_APP_APP_ID,
  environment: 'production' as const,
};

root.render(
  <ChatSDKProvider config={sdkConfig}>
    <App />
  </ChatSDKProvider>
);

LoginPage.tsx:

import { useChatSDK } from '@traiyani/chatsdk-react';

function LoginPage({ onLogin }) {
  const { login } = useChatSDK();

  const handleWebsiteLogin = async (websiteUser) => {
    // ... your website login logic ...

    await login({
      id: websiteUser.id,
      name: websiteUser.name,
      email: websiteUser.email,
    });

    onLogin();
  };

  return <button onClick={() => handleWebsiteLogin(myUser)}>Login</button>;
}

ProductPage.tsx:

import { useState } from 'react';
import { ChatPanel } from '@traiyani/chatsdk-react';

function ProductPage({ product }) {
  const [showChat, setShowChat] = useState(false);

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.price} QAR</p>

      <button onClick={() => setShowChat(true)}>Chat with Seller</button>

      <ChatPanel
        visible={showChat}
        onVisibleChange={setShowChat}
        mode="chat"
        targetUser={{ id: product.ownerId }}
        product={{
          productId: product.id,
          productName: product.name,
          productImage: product.image,
          price: product.price,
          currency: 'QAR',
        }}
        chatMetadata={{ source: 'product-page' }}
        locale="en"
        onError={(err) => console.error('Chat error:', err.message)}
      />
    </div>
  );
}

Navbar.tsx (conversation list + unread badge):

import { useState, useRef } from 'react';
import { ChatPanel, useChatSDK } from '@traiyani/chatsdk-react';
import type { ChatPanelRef } from '@traiyani/chatsdk-react';

function Navbar() {
  const { logout } = useChatSDK();
  const [showMessages, setShowMessages] = useState(false);
  const [unread, setUnread] = useState(0);

  const handleLogout = async () => {
    await logout();
    // ... your website logout logic ...
  };

  return (
    <nav>
      <button onClick={() => setShowMessages(true)}>
        Messages
        {unread > 0 && <span className="badge">{unread}</span>}
      </button>

      <ChatPanel
        visible={showMessages}
        onVisibleChange={setShowMessages}
        mode="conversations"
        locale="en"
        onUnreadCountChange={(count) => setUnread(count)}
      />

      <button onClick={handleLogout}>Logout</button>
    </nav>
  );
}

5. ChatPanel Props Reference

| Prop | Type | Required | Default | Description | |---|---|---|---|---| | visible | boolean | Yes | — | Controls panel visibility. | | onVisibleChange | (visible: boolean) => void | Yes | — | Called when panel wants to close. Use with visible for two-way binding. | | mode | 'chat' \| 'conversations' | No | 'conversations' | 'chat' opens a direct chat popup. 'conversations' opens the conversation list with chat window. | | targetUser | TargetUser | For mode="chat" | — | The other party to chat with. See Target User Resolution. | | product | ProductContext | No | — | Product metadata to attach to the conversation. | | chatMetadata | Record<string, any> | No | — | Additional metadata for the chat (e.g., source, ad type). | | externalGroupId | string | No | — | Custom group ID. If omitted, the SDK generates one via SHA-256. | | locale | 'en' \| 'ar' | No | — | Language. Reactive — changing it switches the language automatically. | | onError | (error: Error) => void | No | — | Callback for errors. The panel catches all internal errors and calls this. | | onUnreadCountChange | (count: number) => void | No | — | Callback when unread conversation count changes (polled every 30s). |

TargetUser

interface TargetUser {
  id?: string;     // External user ID — if present, skip verification
  name?: string;   // Display name
  email?: string;  // Email
  phone?: string;  // Phone number (stored as metadata)
}

ProductContext

interface ProductContext {
  productId: string;
  productName: string;
  productImage?: string;
  price?: number;
  currency?: string;
  category?: string;
  productMetadata?: Record<string, any>;
}

6. Ref Methods

Access methods on the <ChatPanel /> via a React ref:

import { useRef } from 'react';
import { ChatPanel } from '@traiyani/chatsdk-react';
import type { ChatPanelRef } from '@traiyani/chatsdk-react';

function MyComponent() {
  const chatPanelRef = useRef<ChatPanelRef>(null);

  // Logout from chat (SDK + socket + clear tokens)
  const handleLogout = async () => {
    await chatPanelRef.current?.logout();
  };

  // Get current unread conversations count
  const checkUnread = async () => {
    const count = await chatPanelRef.current?.getUnreadCount();
    console.log('Unread:', count);
  };

  return <ChatPanel ref={chatPanelRef} visible={showChat} onVisibleChange={setShowChat} />;
}

| Method | Returns | Description | |---|---|---| | logout() | Promise<void> | Full cleanup: SDK logout + socket disconnect + clear tokens + close panel | | getUnreadCount() | Promise<number> | Returns the number of conversations with unread messages |


7. Theme Support

import { useTheme } from '@traiyani/chatsdk-react';

function ThemeSwitch() {
  const { theme, actualTheme, setTheme, toggleTheme } = useTheme();

  return (
    <div>
      <p>Current: {actualTheme}</p>
      <button onClick={toggleTheme}>Toggle</button>
      <button onClick={() => setTheme('dark')}>Dark</button>
      <button onClick={() => setTheme('light')}>Light</button>
      <button onClick={() => setTheme('auto')}>Auto (system)</button>
    </div>
  );
}

8. Internationalization (i18n)

Supported languages: English (en), Arabic (ar with RTL).

The <ChatPanel /> accepts a reactive locale prop and handles language switching internally. No manual calls needed.

<ChatPanel
  visible={showChat}
  onVisibleChange={setShowChat}
  mode="conversations"
  locale={currentLocale}
/>

If you need direct access to i18n functions:

import { useI18n } from '@traiyani/chatsdk-react';

function MyComponent() {
  const { t, changeLanguage, getCurrentLanguage, isRTL } = useI18n();

  return (
    <div>
      <h1>{t('conversations_title')}</h1>
      <button onClick={() => changeLanguage('ar')}>Switch to Arabic</button>
    </div>
  );
}

9. TypeScript Support

Full type declarations are included. No extra @types/* packages needed.

import type {
  ChatSDKConfig,
  ChatSDKUser,
  ChatSDKMessage,
  ChatSDKConversation,
  ChatSDKLoginUser,
  ProductContext,
  TargetUser,
  Product,
  ChatState,
  ChatPanelProps,
  ChatPanelRef,
} from '@traiyani/chatsdk-react';

10. Troubleshooting

| Problem | Solution | |---------|----------| | "SDK not initialized" | Ensure <ChatSDKProvider> wraps your app in index.tsx before any SDK usage | | "No logged-in user" | Call useChatSDK().login() after your website login before opening ChatPanel | | WebSocket not connecting | Verify apiBaseUrl is correct and reachable, check CORS configuration | | CSS not applying | CSS is auto-injected on import. If missing, clear node_modules and reinstall | | Authentication fails | Verify apiBaseUrl and appId match your chat server configuration | | Panel not showing | Ensure visible={true} is passed and onVisibleChange updates the state | | Language not updating | Use useI18n() hook instead of direct t() import for reactive translations |

License

MIT