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.
import {
BranchPickerPrimitive,
MessagePrimitive,
} from "@assistant-ui/react";
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
function AssistantMessage() {
return (
<MessagePrimitive.Root className="flex flex-col items-start gap-1">
<div className="rounded-2xl bg-muted px-4 py-2.5 text-sm">
<MessagePrimitive.Parts />
</div>
<BranchPickerPrimitive.Root className="inline-flex items-center gap-0.5 text-xs">
<BranchPickerPrimitive.Previous className="flex size-6 items-center justify-center rounded-md disabled:opacity-30">
<ChevronLeftIcon className="size-3.5" />
</BranchPickerPrimitive.Previous>
<span>
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
</span>
<BranchPickerPrimitive.Next className="flex size-6 items-center justify-center rounded-md disabled:opacity-30">
<ChevronRightIcon className="size-3.5" />
</BranchPickerPrimitive.Next>
</BranchPickerPrimitive.Root>
</MessagePrimitive.Root>
);
}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.
Inside a Message Footer
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: