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

react-ai-chatkit

v1.1.0

Published

A customizable React and TypeScript chat UI component for AI assistants, SaaS applications, and chatbot interfaces.

Downloads

978

Readme

🤖 React AI ChatKit

A customizable React + TypeScript chat component for AI assistants, SaaS applications, internal tools, and chatbot interfaces.

npm version npm downloads License GitHub stars


📸 Preview


✨ Features

  • 🎨 Light & Dark themes with a consistent internal color system
  • 🎨 Custom primary color
  • 🤖 AI & User avatars (image or custom fallback)
  • 🎛️ Fully customizable header, empty state, input, and send button
  • 💬 Modern chat interface
  • 📝 Markdown rendering (headings, lists, links, blockquotes, inline code, tables)
  • 📄 Syntax highlighted code blocks with copy button
  • 📋 Copy message button with accessible feedback
  • 🔄 Regenerate last assistant response (optional)
  • ⌨️ Enter to send, Shift + Enter for new lines
  • ⌨️ Animated typing indicator and send-button loading state
  • ⏰ Message timestamps with optional formatter
  • 📱 Responsive design with no horizontal overflow
  • ⚡ TypeScript support with exported types

What's new in v1.1.0

  • Regenerate response — optional onRegenerate callback adds a regenerate button to the last assistant message
  • Message actions — copy and regenerate actions with accessible keyboard support
  • Streaming-friendly — progressive assistant content updates render cleanly without visual glitches
  • Empty & disabled states — improved visual handling for empty conversations and disabled input

All existing v1.0.x functionality is fully preserved. No breaking changes.


📦 Installation

npm install react-ai-chatkit

or

yarn add react-ai-chatkit

or

pnpm add react-ai-chatkit

🚀 Quick Start

import { AIChatBox } from "react-ai-chatkit";
import type { Message } from "react-ai-chatkit";

const messages: Message[] = [
  {
    id: "1",
    text: "Hello! How can I help you?",
    sender: "ai",
  },
];

export default function App() {
  return (
    <AIChatBox
      messages={messages}
      onSendMessage={(message) => console.log(message)}
    />
  );
}

🎨 Customization

import { AIChatBox } from "react-ai-chatkit";
import type { Message } from "react-ai-chatkit";

const messages: Message[] = [
  {
    id: "1",
    text: "Hello! How can I help you?",
    sender: "ai",
    timestamp: "10:00",
  },
];

export default function App() {
  return (
    <AIChatBox
      messages={messages}
      onSendMessage={(message) => console.log(message)}
      title="AI Assistant"
      subtitle="Online"
      theme="light"
      primaryColor="#6366f1"
      width="500px"
      height="600px"
      aiAvatarFallback={<span>🤖</span>}
      userAvatarFallback={<span>🙂</span>}
      emptyStateTitle="How can I help?"
      emptyStateDescription="Ask me anything."
      placeholder="Type your message..."
      maxLength={500}
      autoFocus
      sendButtonText="Send"
      timestampFormatter={(timestamp) => `at ${timestamp}`}
    />
  );
}

Custom header, send button, and message styles

<AIChatBox
  messages={messages}
  onSendMessage={handleSend}
  header={
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <strong>Support</strong>
    </div>
  }
  headerActions={<button type="button">Settings</button>}
  sendButtonContent={
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
      <path d="m5 12 4 4L19 6" />
    </svg>
  }
  userMessageStyle={{ marginTop: 4 }}
  aiMessageClassName="ai-message-box"
/>

Custom class names

<AIChatBox
  messages={messages}
  onSendMessage={handleSend}
  containerClassName="my-chat-wrapper"
  messageListClassName="my-chat-messages"
  inputClassName="my-chat-input"
  sendButtonClassName="my-chat-send"
/>

Each prop is merged with the built-in class on the same element, so existing styling is preserved and you can layer your own CSS on top. containerClassName targets the root chat container, messageListClassName the scrollable messages area, inputClassName the textarea, and sendButtonClassName the send button.

Placeholder and send button label

<AIChatBox
  messages={messages}
  onSendMessage={handleSend}
  placeholder="Ask me anything..."
  sendButtonLabel="Submit message"
/>

placeholder customizes the textarea placeholder and sendButtonLabel sets the send button's accessible label/title without changing its visual content.

Typing / sending state

<AIChatBox
  messages={messages}
  onSendMessage={handleSend}
  isTyping={isWaiting}
  isSending={isWaiting} // disables the send button and shows a spinner
/>

Regenerate last response

<AIChatBox
  messages={messages}
  onSendMessage={handleSend}
  onRegenerate={() => {
    // Re-trigger your AI generation logic
    // The component shows a regenerate button on the last AI message
  }}
/>

When onRegenerate is provided, a regenerate button appears on the last AI message. Hover or focus the message to reveal the action buttons. The button is keyboard accessible and has an appropriate accessible label.

Message actions

Each assistant message shows action buttons on hover (or always on touch devices):

  • Copy — copies the message text to the clipboard with visual feedback
  • Regenerate — shown only on the last AI message when onRegenerate is provided

Both buttons are keyboard accessible with visible focus indicators and aria-label attributes.


⚙️ Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | messages | Message[] | Required | Chat messages | | onSendMessage | (message: string) => void | undefined | Called when a message is sent | | title | string | "React AI Chatbox" | Header title | | subtitle | string | undefined | Optional header subtitle | | header | ReactNode | undefined | Replaces the default header content | | headerActions | ReactNode | undefined | Action content shown on the right side of the header | | theme | "light" | "dark" | "dark" | Theme | | primaryColor | string | #7c3aed | Primary accent color | | width | string | number | "450px" | Component width | | height | string | number | "520px" | Component height | | placeholder | string | "Type your message..." | Input placeholder | | disabled | boolean | false | Disable input | | isTyping | boolean | false | Show typing indicator | | isSending | boolean | false | Disable send and show a spinner while sending | | showHeader | boolean | true | Show header | | showAvatars | boolean | true | Show avatars | | aiAvatar | string | undefined | AI avatar image URL | | userAvatar | string | undefined | User avatar image URL | | aiAvatarFallback | ReactNode | Robot icon | Content shown when no AI avatar image is set | | userAvatarFallback | ReactNode | Person icon | Content shown when no user avatar image is set | | aiMessageClassName | string | undefined | Class added to AI message rows | | aiMessageStyle | React.CSSProperties | undefined | Style added to AI message rows | | userMessageClassName | string | undefined | Class added to user message rows | | userMessageStyle | React.CSSProperties | undefined | Style added to user message rows | | showCopyButton | boolean | true | Show the message copy button | | showSendButton | boolean | true | Show the send button | | sendButtonText | string | "Ask AI" | Send button text (and accessible label for custom content) | | sendButtonContent | ReactNode | undefined | Custom send button content/icon | | sendButtonLabel | string | "Send" | Accessible label (title/aria-label) of the send button | | showTimestamps | boolean | true | Show timestamps | | timestampFormatter | (timestamp: string) => string | undefined | Format the rendered timestamp | | emptyStateTitle | string | "Start a conversation" | Empty state title | | emptyStateDescription | string | "Send a message to begin chatting." | Empty state description | | emptyStateContent | ReactNode | undefined | Replaces the default empty state content | | inputProps | TextareaHTMLAttributes<HTMLTextAreaElement> | undefined | Native textarea props | | inputClassName | string | undefined | Class added to the textarea | | inputStyle | React.CSSProperties | undefined | Style added to the textarea | | inputContainerClassName | string | undefined | Class added to the input container (footer) | | inputContainerStyle | React.CSSProperties | undefined | Style added to the input container (footer) | | maxInputLength | number | undefined | Maximum input length (deprecated alias of maxLength) | | maxLength | number | undefined | Maximum input length; prevents typing beyond the limit | | autoFocus | boolean | false | Focus the textarea automatically on initial render | | className | string | undefined | Class added to the component root | | containerClassName | string | undefined | Additional class added to the component root | | messageListClassName | string | undefined | Additional class added to the scrollable messages container | | sendButtonClassName | string | undefined | Additional class added to the send button | | style | React.CSSProperties | undefined | Style added to the component root | | onRegenerate | () => void | undefined | Callback when the regenerate button is clicked on the last AI message |

Message type

interface Message {
  id: string;
  text: string;
  sender: "user" | "ai";
  timestamp?: string;
}

Theme colors

The internal color system is exported for custom styles:

import { getChatColors } from "react-ai-chatkit";

const colors = getChatColors("dark");
// { background, text, border, aiBubble, inputBackground, mutedText, success }

📄 Markdown Example

const aiMessage = {
  sender: "ai",
  text: `
# Welcome

Here is some code:

\`\`\`tsx
function Button() {
  return <button>Hello</button>;
}
\`\`\`
`,
};

Markdown with tables, lists, quotes, and links is supported out of the box.


📚 TypeScript Usage

import { AIChatBox } from "react-ai-chatkit";
import type {
  AIChatBoxProps,
  ChatColors,
  ChatTheme,
  Message,
} from "react-ai-chatkit";

const config: AIChatBoxProps = {
  messages: [],
  onSendMessage: (message: string) => console.log(message),
  theme: "dark",
};

export default function App() {
  return <AIChatBox {...config} />;
}

🔗 Links


📄 License

MIT