Join our Discord Community

React AI Actions

Interactive action buttons for AI chat interfaces. Build engaging conversational experiences with React, Next.js, and TypeScript, featuring tooltips and accessibility support with shadcn/ui integration.

Trying to implement AI Elements?

Join our Discord community for help from other developers.


Users expect copy buttons on AI responses. Add them or watch people right-click everything like savages. This component puts action buttons where they belong—right after the message content, not buried in some menu.

Chat message actions

Quick action buttons for AI responses with tooltips:

Loading component...

Built with TypeScript and shadcn/ui for React applications, so it plays nice with your existing Next.js setup. Tooltips work properly, focus handling doesn't break tab navigation, and screen readers won't hate you.

Installation

npx shadcn@latest add https://www.shadcn.io/registry/ai.json
npx shadcn@latest add https://www.shadcn.io/registry/ai.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/ai.json
bunx shadcn@latest add https://www.shadcn.io/registry/ai.json

Usage

import { Actions, Action } from "@/components/ai/actions";
import { ThumbsUpIcon } from "lucide-react";

<Actions className="mt-2">
  <Action label="Like">
    <ThumbsUpIcon className="size-4" />
  </Action>
</Actions>;

Why most action implementations suck

Most developers either forget action buttons entirely or put them in weird places. Users look for copy buttons immediately after reading a response—not in a dropdown menu, not in a toolbar somewhere else.

This React component uses ghost buttons by default because bordered buttons look busy in chat interfaces. If you disagree, use the variant prop. The buttons are 44px touch targets because mobile users need bigger tap areas (trust me on this one).

Usage with Vercel AI SDK

Real example with copy and regenerate using the Vercel AI SDK useChat hook in React applications:

"use client";

import { Actions, Action } from "@/components/ai/actions";
import { Message, MessageContent } from "@/components/ai/message";
import {
  Conversation,
  ConversationContent,
} from "@/components/ai/conversation";
import { RefreshCcwIcon, CopyIcon } from "lucide-react";
import { useChat } from "@ai-sdk/react";

export default function Chat() {
  const { messages, regenerate } = useChat();

  return (
    <Conversation>
      <ConversationContent>
        {messages.map((message, index) => (
          <Message from={message.role} key={message.id}>
            <MessageContent>
              {message.content}
              {message.role === "assistant" &&
                index === messages.length - 1 && (
                  <Actions className="mt-2">
                    <Action onClick={() => regenerate()} label="Retry">
                      <RefreshCcwIcon className="size-4" />
                    </Action>
                    <Action
                      onClick={() =>
                        navigator.clipboard.writeText(message.content)
                      }
                      label="Copy"
                    >
                      <CopyIcon className="size-4" />
                    </Action>
                  </Actions>
                )}
            </MessageContent>
          </Message>
        ))}
      </ConversationContent>
    </Conversation>
  );
}

Examples

Multi-select actions toolbar

Advanced toolbar with grouped actions and keyboard shortcuts:

Loading component...

Contextual actions with loading states

Show different actions based on message state with loading indicators:

Loading component...

Features

  • Action buttons that don't look like an afterthought in React applications
  • Tooltips that actually help (not just label repetition)
  • Proper keyboard navigation that doesn't break in Next.js projects
  • Clipboard API integration (falls back to execCommand for older browsers)
  • Works with any Vercel AI SDK setup in JavaScript applications
  • Complete TypeScript definitions that make sense
  • Free open source component designed for conversational AI interfaces
  • Built for modern React frameworks and code generation tools

API Reference

Actions

Container for grouping action buttons.

PropTypeDescription
...propsHTMLAttributes<HTMLDivElement>HTML attributes to spread to the root div

Action

Individual action button with optional tooltip.

PropTypeDefaultDescription
tooltipstring-Optional tooltip text shown on hover
labelstring-Accessible label for screen readers
variantButtonVariant"ghost"Button variant from shadcn/ui
sizeButtonSize"sm"Button size preset
...propsComponentProps<Button>-Spreads to underlying Button component

Keyboard interactions

Actions support full keyboard navigation for accessibility:

KeyDescription
TabMove focus to next action button
Shift + TabMove focus to previous action button
Enter / SpaceActivate focused action
EscapeClose tooltip if open

Common gotchas

Tooltip z-index issues: Our tooltips use Radix Portal so they don't get buried under modals in React applications. Most implementations mess this up.

Users spam click async actions: Always disable the button during API calls in Next.js projects. Otherwise users will click "Regenerate" five times and wonder why their app is broken.

Forgetting disabled state explanations: If an action is disabled, the tooltip should explain why in JavaScript applications. "Copy (generating...)" is better than just a grayed-out button.

Touch targets too small: 44px minimum for mobile. This React component handles this with padding, but if you override styles, remember this.

Missing screen reader support: Even if you have visible tooltips, add aria-label for TypeScript accessibility. Screen reader users shouldn't have to guess what buttons do.

Integration with other components

Drop these into Message components for instant chat interfaces in React applications. Pairs well with Branch if you're building version control for AI responses in Next.js projects. This free open source component family is designed to work together without style conflicts in modern JavaScript frameworks.

Questions developers actually ask