BranchPicker

Navigate between message branches, which are alternative responses the user can flip through.

The BranchPicker primitive lets users navigate between message branches, which are alternative responses generated by editing a message or regenerating a reply. It's used alongside ActionBar inside message components.

What is assistant-ui?

assistant-ui is a set of React components for building AI chat interfaces. It provides unstyled primitives that handle state management, streaming, and accessibility — you bring the design.

1 / 1

Quick Start

Minimal example:

import { BranchPickerPrimitive } from "@assistant-ui/react";

<BranchPickerPrimitive.Root>
  <BranchPickerPrimitive.Previous></BranchPickerPrimitive.Previous>
  <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
  <BranchPickerPrimitive.Next></BranchPickerPrimitive.Next>
</BranchPickerPrimitive.Root>

Root renders a <div>, Previous and Next render <button> elements that auto-disable at boundaries. Number and Count render plain text (the current branch index and total count).

BranchPicker must be placed inside a MessagePrimitive.Root because it reads branch state from the nearest message context.

Runtime setup: primitives require runtime context. Wrap your UI in AssistantRuntimeProvider with a runtime (for example useLocalRuntime(...)). See Pick a Runtime.

Core Concepts

Branch Navigation

Previous and Next buttons automatically disable at boundaries. Previous is disabled on the first branch, and Next is disabled on the last. Both also disable while the thread is running if the runtime doesn't support switchBranchDuringRun.

Number & Count

Number and Count are text-only primitives that render raw numbers with no wrapping element. Use a <span> if you need to style them:

<span className="tabular-nums">
  <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
</span>

hideWhenSingleBranch

The hideWhenSingleBranch prop on Root hides the entire picker when there's only one branch. This is a common production pattern to reduce visual clutter:

<BranchPickerPrimitive.Root hideWhenSingleBranch>
  <BranchPickerPrimitive.Previous></BranchPickerPrimitive.Previous>
  <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
  <BranchPickerPrimitive.Next></BranchPickerPrimitive.Next>
</BranchPickerPrimitive.Root>

Context Requirement

BranchPicker reads branch state from the nearest message context. It must be placed inside a MessagePrimitive.Root, either directly or nested inside your message component.

Parts

Root

Container with optional hideWhenSingleBranch. Renders a <div> element unless asChild is set.

<BranchPickerPrimitive.Root hideWhenSingleBranch className="inline-flex items-center gap-1">
  <BranchPickerPrimitive.Previous></BranchPickerPrimitive.Previous>
  <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
  <BranchPickerPrimitive.Next></BranchPickerPrimitive.Next>
</BranchPickerPrimitive.Root>

Prop

Type

Previous

Button that selects the previous branch. Renders a <button> element unless asChild is set.

<BranchPickerPrimitive.Previous>Previous</BranchPickerPrimitive.Previous>

Next

Button that selects the next branch. Renders a <button> element unless asChild is set.

<BranchPickerPrimitive.Next>Next</BranchPickerPrimitive.Next>

Number

Displays the current branch number.

<BranchPickerPrimitive.Number />

Count

Displays the total number of branches for the current message.

<BranchPickerPrimitive.Count />

Patterns

Standard Picker with Icons

import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";

<BranchPickerPrimitive.Root
  hideWhenSingleBranch
  className="inline-flex items-center gap-1 text-xs text-muted-foreground"
>
  <BranchPickerPrimitive.Previous className="size-6 rounded-md hover:bg-muted disabled:opacity-30">
    <ChevronLeftIcon className="size-3.5" />
  </BranchPickerPrimitive.Previous>
  <span className="tabular-nums">
    <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
  </span>
  <BranchPickerPrimitive.Next className="size-6 rounded-md hover:bg-muted disabled:opacity-30">
    <ChevronRightIcon className="size-3.5" />
  </BranchPickerPrimitive.Next>
</BranchPickerPrimitive.Root>

Custom Elements with asChild

<BranchPickerPrimitive.Previous asChild>
  <MyIconButton tooltip="Previous branch">
    <ChevronLeftIcon />
  </MyIconButton>
</BranchPickerPrimitive.Previous>

The primitive's disabled state and click handler merge onto your element.

The most common pattern places the BranchPicker alongside an ActionBar in a message footer:

function AssistantMessage() {
  return (
    <MessagePrimitive.Root>
      <div className="rounded-xl bg-muted p-3">
        <MessagePrimitive.Parts />
      </div>
      <div className="flex items-center justify-between">
        <BranchPickerPrimitive.Root hideWhenSingleBranch>
          {/* prev / number / count / next */}
        </BranchPickerPrimitive.Root>
        <ActionBarPrimitive.Root>
          <ActionBarPrimitive.Copy>Copy</ActionBarPrimitive.Copy>
          <ActionBarPrimitive.Reload>Reload</ActionBarPrimitive.Reload>
        </ActionBarPrimitive.Root>
      </div>
    </MessagePrimitive.Root>
  );
}

Relationship to Components

The shadcn Thread component includes a BranchPicker in both AssistantMessage and UserMessage footers, with hideWhenSingleBranch enabled. If the default layout works, use the component. Reach for BranchPickerPrimitive directly when you need a custom position, different styling, or a non-standard branch navigation experience.

API Reference

For full prop details on every part, see the BranchPickerPrimitive API Reference.

Related: