CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-copilotkit--react-ui

Production-ready React UI components library for building deeply-integrated AI assistants and copilots

Overview
Eval results
Files

message-components.mddocs/

Message Components

Default and customizable components for rendering different message types in the chat interface. These components can be used as-is or replaced with custom implementations.

Capabilities

AssistantMessage

Default component for rendering AI assistant messages. Displays markdown content, handles loading states, and provides message controls.

/**
 * Default assistant message rendering component
 * @param props - Assistant message configuration and callbacks
 * @returns Rendered assistant message with controls
 */
function AssistantMessage(props: AssistantMessageProps): JSX.Element;

interface AssistantMessageProps {
  /** The AI message content */
  message?: AIMessage;

  /** Whether this is the most recent message */
  isCurrentMessage?: boolean;

  /** Whether response is loading (thinking state) */
  isLoading: boolean;

  /** Whether response is actively streaming */
  isGenerating: boolean;

  /** Callback to regenerate this message */
  onRegenerate?: () => void;

  /** Callback when message is copied */
  onCopy?: (message: string) => void;

  /** Callback for positive feedback */
  onThumbsUp?: (message: Message) => void;

  /** Callback for negative feedback */
  onThumbsDown?: (message: Message) => void;

  /** Custom markdown component renderers */
  markdownTagRenderers?: ComponentsMap;

  /** Custom image renderer component */
  ImageRenderer?: React.ComponentType<ImageRendererProps>;

  /**
   * @deprecated Use message property instead
   * Note: Despite being deprecated, this property is currently REQUIRED
   */
  rawData: any;

  /** @deprecated Use message.generativeUI() instead */
  subComponent?: React.JSX.Element;
}

interface AIMessage {
  id: string;
  role: "assistant";
  content: string;
  generativeUI?: () => React.ReactNode;
  agentName?: string;
  state?: any;
  image?: ImageData;
}

Usage Example:

import { AssistantMessage } from "@copilotkit/react-ui";

function CustomChat() {
  const message = {
    id: "msg-1",
    role: "assistant" as const,
    content: "Here's how to implement that feature:\n\n```typescript\nconst result = compute();\n```",
  };

  return (
    <AssistantMessage
      message={message}
      rawData={message} // Required despite being deprecated
      isCurrentMessage={true}
      isLoading={false}
      isGenerating={false}
      onRegenerate={() => console.log("Regenerate")}
      onCopy={(text) => navigator.clipboard.writeText(text)}
      onThumbsUp={(msg) => console.log("Liked:", msg.id)}
      onThumbsDown={(msg) => console.log("Disliked:", msg.id)}
    />
  );
}

UserMessage

Default component for rendering user messages. Handles both text messages and messages with image attachments.

/**
 * Default user message rendering component
 * @param props - User message content and image renderer
 * @returns Rendered user message
 */
function UserMessage(props: UserMessageProps): JSX.Element;

interface UserMessageProps {
  /** The user message content */
  message?: UserMessage;

  /** Image renderer component for displaying attachments */
  ImageRenderer: React.ComponentType<ImageRendererProps>;

  /**
   * @deprecated Use message property instead
   * Note: Despite being deprecated, this property is currently REQUIRED
   */
  rawData: any;
}

interface UserMessage {
  id: string;
  role: "user";
  content: string;
  image?: ImageData;
}

Usage Example:

import { UserMessage, ImageRenderer } from "@copilotkit/react-ui";

function CustomChat() {
  const message = {
    id: "msg-2",
    role: "user" as const,
    content: "Can you help me with this diagram?",
    image: {
      format: "png",
      bytes: "base64-encoded-image-data",
    },
  };

  return (
    <UserMessage
      message={message}
      rawData={message} // Required despite being deprecated
      ImageRenderer={ImageRenderer}
    />
  );
}

ImageRenderer

Default component for rendering images in messages. Displays base64-encoded images with error handling.

/**
 * Default image rendering component
 * @param props - Image data and optional text content
 * @returns Rendered image element
 */
function ImageRenderer(props: ImageRendererProps): JSX.Element;

interface ImageRendererProps {
  /** Image data with format and encoded bytes */
  image: ImageData;

  /** Optional text content to display with image */
  content?: string;

  /** Additional CSS class */
  className?: string;
}

interface ImageData {
  /** Image format (e.g., "png", "jpeg", "gif") */
  format: string;

  /** Base64-encoded image bytes */
  bytes: string;
}

Usage Example:

import { ImageRenderer } from "@copilotkit/react-ui";

function CustomImageDisplay() {
  const imageData = {
    format: "png",
    bytes: "iVBORw0KGgoAAAANSUhEUgAAAAUA...", // base64 data
  };

  return (
    <ImageRenderer
      image={imageData}
      content="Screenshot of the error"
      className="my-custom-image"
    />
  );
}

Markdown

Markdown rendering component using react-markdown with support for GitHub Flavored Markdown, math equations, and custom renderers.

/**
 * Markdown rendering component with GFM and math support
 * @param props - Markdown content and custom component renderers
 * @returns Rendered markdown content
 */
function Markdown(props: MarkdownProps): JSX.Element;

interface MarkdownProps {
  /** Markdown content string to render */
  content: string;

  /** Custom component renderers for markdown elements */
  components?: ComponentsMap;
}

type ComponentsMap<T extends Record<string, object> = Record<string, object>> = {
  [K in keyof T]: React.FC<{ children?: React.ReactNode } & T[K]>;
};

Usage Example:

import { Markdown } from "@copilotkit/react-ui";

function CustomMarkdownDisplay() {
  const content = `
# Title

Here's some **bold** and *italic* text.

\`\`\`typescript
const greeting = "Hello, World!";
console.log(greeting);
\`\`\`

- List item 1
- List item 2

| Column 1 | Column 2 |
|----------|----------|
| Data 1   | Data 2   |
`;

  return (
    <Markdown
      content={content}
      components={{
        h1: ({ children }) => (
          <h1 className="custom-heading">{children}</h1>
        ),
        code: ({ children }) => (
          <code className="custom-code">{children}</code>
        ),
      }}
    />
  );
}

Custom Message Renderers

Props interfaces for creating fully custom message rendering components.

interface RenderMessageProps {
  /** The message to render */
  message: Message;

  /** Whether chat is currently in progress */
  inProgress: boolean;

  /** Message index in the array */
  index: number;

  /** Whether this is the most recent message */
  isCurrentMessage: boolean;

  /** Result from action execution if applicable */
  actionResult?: string;

  /** Assistant message component to use */
  AssistantMessage?: React.ComponentType<AssistantMessageProps>;

  /** User message component to use */
  UserMessage?: React.ComponentType<UserMessageProps>;

  /** Image renderer component to use */
  ImageRenderer?: React.ComponentType<ImageRendererProps>;

  /** Callback to regenerate message */
  onRegenerate?: (messageId: string) => void;

  /** Callback when message is copied */
  onCopy?: (message: string) => void;

  /** Callback for positive feedback */
  onThumbsUp?: (message: Message) => void;

  /** Callback for negative feedback */
  onThumbsDown?: (message: Message) => void;

  /** Custom markdown renderers */
  markdownTagRenderers?: ComponentsMap;
}

type Message = AIMessage | UserMessage;

Usage Example:

import { CopilotChat } from "@copilotkit/react-ui";
import type { RenderMessageProps } from "@copilotkit/react-ui";

function CustomMessageRenderer({
  message,
  isCurrentMessage,
  AssistantMessage,
  UserMessage,
  ImageRenderer,
  ...props
}: RenderMessageProps) {
  // Add custom wrapper or logic
  return (
    <div className="custom-message-wrapper">
      <div className="message-metadata">
        <span>{new Date(message.timestamp).toLocaleTimeString()}</span>
      </div>
      {message.role === "assistant" && AssistantMessage && (
        <AssistantMessage
          message={message}
          rawData={message} // Required despite being deprecated
          isCurrentMessage={isCurrentMessage}
          ImageRenderer={ImageRenderer}
          {...props}
        />
      )}
      {message.role === "user" && UserMessage && (
        <UserMessage
          message={message}
          rawData={message} // Required despite being deprecated
          ImageRenderer={ImageRenderer}
        />
      )}
    </div>
  );
}

function App() {
  return (
    <CopilotChat
      RenderMessage={CustomMessageRenderer}
    />
  );
}

Error Message Component

Interface for rendering error messages in the chat.

interface ErrorMessageProps {
  /** Error information */
  error: ChatError;

  /** Whether this is the most recent message */
  isCurrentMessage?: boolean;

  /** Callback to regenerate/retry */
  onRegenerate?: () => void;

  /** Callback when error is copied */
  onCopy?: (message: string) => void;
}

interface ChatError {
  /** Error message text */
  message: string;

  /** Operation that caused the error */
  operation?: string;

  /** Error timestamp */
  timestamp: number;
}

Usage Example:

import { CopilotChat } from "@copilotkit/react-ui";
import type { ErrorMessageProps } from "@copilotkit/react-ui";

function CustomErrorMessage({
  error,
  onRegenerate,
}: ErrorMessageProps) {
  return (
    <div className="custom-error">
      <div className="error-icon">⚠️</div>
      <div className="error-content">
        <h4>Something went wrong</h4>
        <p>{error.message}</p>
        {error.operation && <small>During: {error.operation}</small>}
      </div>
      <button onClick={onRegenerate}>Retry</button>
    </div>
  );
}

function App() {
  return (
    <CopilotChat
      ErrorMessage={CustomErrorMessage}
    />
  );
}

Suggestions Components

Components for rendering chat suggestions.

/**
 * Default suggestions list renderer
 * @param props - Suggestions array and click handler
 * @returns Rendered suggestions list
 */
function RenderSuggestionsList(props: RenderSuggestionsListProps): JSX.Element;

interface RenderSuggestionsListProps {
  /** Array of suggestion items */
  suggestions: CopilotChatSuggestion[];

  /** Click handler for suggestions */
  onSuggestionClick: (message: string) => void;
}

interface CopilotChatSuggestion {
  /** Suggestion title/text displayed to user */
  title: string;

  /** Message to send when suggestion is clicked */
  message: string;

  /** Whether suggestion is still being generated */
  partial?: boolean;

  /** Optional CSS class */
  className?: string;
}

Usage Example:

import { CopilotChat } from "@copilotkit/react-ui";
import type { RenderSuggestionsListProps } from "@copilotkit/react-ui";

function CustomSuggestionsList({
  suggestions,
  onSuggestionClick,
}: RenderSuggestionsListProps) {
  return (
    <div className="custom-suggestions">
      <h4>Try asking:</h4>
      <div className="suggestion-grid">
        {suggestions.map((suggestion, i) => (
          <button
            key={i}
            onClick={() => onSuggestionClick(suggestion.message)}
            disabled={suggestion.partial}
            className={suggestion.className}
          >
            {suggestion.title}
            {suggestion.partial && " ..."}
          </button>
        ))}
      </div>
    </div>
  );
}

function App() {
  return (
    <CopilotChat
      suggestions={[
        { title: "Analyze data", message: "Can you analyze my dataset?" },
        { title: "Generate report", message: "Generate a summary report" },
        { title: "Export results", message: "How do I export the results?" },
      ]}
      RenderSuggestionsList={CustomSuggestionsList}
    />
  );
}

RenderSuggestion

Individual suggestion button component. Exported for advanced customization when building custom suggestion lists.

Note: This component is exported as RenderSuggestion from the package (the internal component is named Suggestion but exported with the alias RenderSuggestion).

/**
 * Individual suggestion button component
 * @param props - Suggestion data and click handler
 * @returns Rendered suggestion button
 */
function RenderSuggestion(props: SuggestionProps): JSX.Element | null;

interface SuggestionProps {
  /** Suggestion title to display */
  title: string;

  /** Message to send when clicked */
  message: string;

  /** Whether suggestion is still loading */
  partial?: boolean;

  /** Optional CSS class */
  className?: string;

  /** Click handler */
  onClick: () => void;
}

Usage Example:

import { RenderSuggestion } from "@copilotkit/react-ui";
import type { RenderSuggestionsListProps } from "@copilotkit/react-ui";

function CustomSuggestionsList({
  suggestions,
  onSuggestionClick,
}: RenderSuggestionsListProps) {
  return (
    <div className="custom-suggestions-layout">
      {suggestions.map((suggestion, index) => (
        <RenderSuggestion
          key={index}
          title={suggestion.title}
          message={suggestion.message}
          partial={suggestion.partial}
          className={suggestion.className}
          onClick={() => onSuggestionClick(suggestion.message)}
        />
      ))}
    </div>
  );
}

Messages Container Component

Interface for customizing the messages container that wraps all messages.

interface MessagesProps {
  /** Array of all messages */
  messages: Message[];

  /** Whether chat is in progress */
  inProgress: boolean;

  /** Child elements (typically suggestions) */
  children?: React.ReactNode;

  /** Current chat error if any */
  chatError?: ChatError | null;

  /** Assistant message component */
  AssistantMessage: React.ComponentType<AssistantMessageProps>;

  /** User message component */
  UserMessage: React.ComponentType<UserMessageProps>;

  /** Error message component */
  ErrorMessage?: React.ComponentType<ErrorMessageProps>;

  /** Message renderer */
  RenderMessage: React.ComponentType<RenderMessageProps>;

  /** Image renderer */
  ImageRenderer: React.ComponentType<ImageRendererProps>;

  /** Regenerate callback */
  onRegenerate?: (messageId: string) => void;

  /** Copy callback */
  onCopy?: (message: string) => void;

  /** Thumbs up callback */
  onThumbsUp?: (message: Message) => void;

  /** Thumbs down callback */
  onThumbsDown?: (message: Message) => void;

  /** Custom markdown renderers */
  markdownTagRenderers?: ComponentsMap;
}

Input Component

Interface for customizing the chat input component.

interface InputProps {
  /** Whether chat is in progress */
  inProgress: boolean;

  /** Handler for sending messages */
  onSend: (text: string) => Promise<Message>;

  /** Whether input is visible */
  isVisible?: boolean;

  /** Stop generation handler */
  onStop?: () => void;

  /** Upload handler (file picker trigger) */
  onUpload?: () => void;

  /** Hide stop button */
  hideStopButton?: boolean;
}

Install with Tessl CLI

npx tessl i tessl/npm-copilotkit--react-ui@1.10.1

docs

chat-components.md

customization.md

dev-console.md

hooks.md

index.md

message-components.md

types.md

README.md

tile.json