# ActionBarPrimitive
URL: /docs/api-reference/primitives/action-bar

Buttons for message actions like copy, edit, reload, speak, and feedback.

***

title: ActionBarPrimitive
description: Buttons for message actions like copy, edit, reload, speak, and feedback.
--------------------------------------------------------------------------------------

Buttons to interact with the message.

import { ParametersTable } from "@/components/docs/tables/ParametersTable";
import { DataAttributesTable } from "@/components/docs/tables/DataAttributesTable";
import { Code } from "@radix-ui/themes";

## Anatomy

```tsx
import { ActionBarPrimitive } from "@assistant-ui/react";

const UserMessageBar = () => (
  <ActionBarPrimitive.Root>
    <ActionBarPrimitive.Edit />
    <ActionBarPrimitive.Copy />
  </ActionBarPrimitive.Root>
);

const AssistantMessageBar = () => (
  <ActionBarPrimitive.Root>
    <ActionBarPrimitive.Reload />
    <ActionBarPrimitive.Copy />
  </ActionBarPrimitive.Root>
);
```

## API Reference

### Container

Containts all parts of the action bar.

This primitive renders a `<div>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveRootProps"
  parameters={[
  {
    name: "asChild",
  },
  {
    name: "hideWhenRunning",
    type: "boolean",
    default: "false",
    description: (
      <span>
        Do not render the ActionBar when the thread is in running state.
      </span>
    ),
  },
  {
    name: "autohide",
    type: '"always" | "not-last" | "never"',
    default: '"never"',
    description: (
      <span>
        Do not render the ActionBar unless the mouse is hovering over the
        message.
        <br />
        <br />
        <Code>"always"</Code>: always autohide.
        <br />
        <Code>"not-last"</Code>; only autohide if the message is not the last
        one in the thread.
      </span>
    ),
  },
  {
    name: "autohideFloat",
    type: '"always" | "single-branch" | "never"',
    default: '"never"',
    description: (
      <span>
        Float the ActionBar during autohide.
        <br />
        <br />
        <Code>"always"</Code>: always float during autohide.
        <br />
        <Code>"single-branch"</Code>: only float if the message is the only
        one in the thread.
        <br />
        <br />
        Note: this only sets `data-floating` on the ActionBar. You need to set
        the appropriate styles on the ActionBar to make it float.
      </span>
    ),
  },
]}
/>

<DataAttributesTable
  data={[
  {
    attribute: "[data-floating]",
    values: "Present when floating",
  },
]}
/>

### Edit

Enables edit mode on user message.

This primitive renders a `<button>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveEditProps"
  parameters={[
  {
    name: "asChild",
  },
]}
/>

### Reload

Regenerates the assistant message.

This primitive renders a `<button>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveReloadProps"
  parameters={[
  {
    name: "asChild",
  },
]}
/>

{" "}

### Copy

Copies the message to the clipboard.

This primitive renders a `<button>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveCopyProps"
  parameters={[
  {
    name: "asChild",
  },
  {
    name: "copiedDuration",
    type: "number",
    description:
      "The duration in milliseconds to change the message status to 'copied'.",
    default: "3000",
  },
]}
/>

<DataAttributesTable
  data={[
  {
    attribute: "[data-copied]",
    values: "Present when the message was recently copied.",
  },
]}
/>

#### Copied state

Show a different icon for a few seconds after the message is copied.

```tsx
<ActionBarPrimitive.Copy>
  <AssistantIf condition={({ message }) => !message.isCopied}>
    <CopyIcon />
  </AssistantIf>
  <AssistantIf condition={({ message }) => message.isCopied}>
    <CopySuccessIcon />
  </AssistantIf>
</ActionBarPrimitive.Copy>
```

or using the `data-copied` attribute:

```tsx
<ActionBarPrimitive.Copy className="group">
  <CopyIcon className="group-data-[copied]:hidden" />
  <CheckIcon className="hidden group-data-[copied]:block" />
</ActionBarPrimitive.Copy>
```

### Speak

Plays the message text as speech.

This primitive renders a `<button>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveSpeakProps"
  parameters={[
  {
    name: "asChild",
  },
]}
/>

### StopSpeaking

Stops the message text from being played as speech.

This primitive renders a `<button>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveStopSpeakingProps"
  parameters={[
  {
    name: "asChild",
  },
]}
/>

### Feedback Positive

Shows a positive feedback submission button.

This primitive renders a `<button>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveFeedbackPositiveProps"
  parameters={[
  {
    name: "asChild",
  },
]}
/>

<DataAttributesTable
  data={[
  {
    attribute: "[data-submitted]",
    values: "Present when positive feedback was submitted.",
  },
]}
/>

### Feedback Negative

Shows a negative feedback submission button.

This primitive renders a `<button>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveFeedbackNegativeProps"
  parameters={[
  {
    name: "asChild",
  },
]}
/>

<DataAttributesTable
  data={[
  {
    attribute: "[data-submitted]",
    values: "Present when negative feedback was submitted.",
  },
]}
/>

### ExportMarkdown

Exports the message content as a Markdown file download by default, or calls a custom export handler when `onExport` is provided.

This primitive renders a `<button>` element unless `asChild` is set.

<ParametersTable
  type="ActionBarPrimitiveExportMarkdownProps"
  parameters={[
  {
    name: "asChild",
  },
  {
    name: "filename",
    type: "string",
    description:
      "The filename for the downloaded Markdown file. Defaults to 'message-{timestamp}.md'. Ignored when onExport is provided.",
  },
  {
    name: "onExport",
    type: "(content: string) => void | Promise<void>",
    description:
      "Optional callback function that receives the message content. When provided, overrides the default Markdown download behavior. Use this to implement custom export logic (PDF, JSON, TXT, etc.).",
  },
]}
/>

#### Examples

Default Markdown export:

```tsx
<ActionBarPrimitive.ExportMarkdown>
  <DownloadIcon />
  Export as Markdown
</ActionBarPrimitive.ExportMarkdown>
```

With custom filename:

```tsx
<ActionBarPrimitive.ExportMarkdown filename="chat-response.md">
  <DownloadIcon />
  Download
</ActionBarPrimitive.ExportMarkdown>
```

Export as PDF (with custom logic):

```tsx
<ActionBarPrimitive.ExportMarkdown
  onExport={async (content) => {
    const pdf = await generatePdf(content);
    downloadFile(pdf, "message.pdf");
  }}
>
  <FileIcon />
  Export PDF
</ActionBarPrimitive.ExportMarkdown>
```

Export as JSON:

```tsx
<ActionBarPrimitive.ExportMarkdown
  onExport={(content) => {
    const json = JSON.stringify({ content, timestamp: Date.now() });
    const blob = new Blob([json], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "message.json";
    a.click();
    URL.revokeObjectURL(url);
  }}
>
  <CodeIcon />
  Export JSON
</ActionBarPrimitive.ExportMarkdown>
```
