ToolGroup

Wrapper for consecutive tool calls with collapsible and styled options.

A wrapper component that groups consecutive tool calls together, displaying them in a collapsible container with auto-expand behavior during streaming.

Outline (default)
Ghost
Muted

Getting Started

Add tool-group

npx shadcn@latest add https://r.assistant-ui.com/tool-group.json

This adds a /components/assistant-ui/tool-group.tsx file to your project, which you can adjust as needed.

Use it in your application

Pass the ToolGroup component to the MessagePrimitive.Parts component

/components/assistant-ui/thread.tsx
import { ToolGroup } from "@/components/assistant-ui/tool-group";

const AssistantMessage = () => {
  return (
    <MessagePrimitive.Root>
      <MessagePrimitive.Parts
        components={{
          ToolGroup,
        }}
      />
    </MessagePrimitive.Root>
  );
};

Variants

Use the variant prop on ToolGroup.Root to change the visual style:

<ToolGroup.Root variant="outline">...</ToolGroup.Root>
<ToolGroup.Root variant="muted">...</ToolGroup.Root>
VariantDescription
defaultNo additional styling
outlineRounded border
mutedMuted background with border

Examples

Streaming Demo (Custom UI + Fallback)

Interactive demo showing tool group with custom tool UIs and ToolFallback working together. Watch as weather cards stream in with loading states, followed by a search tool using the fallback UI.

Click "Start Tool Calls" to see mixed custom UI + fallback

Custom Tool UIs

ToolGroup works with any custom tool UI components:

// Custom Weather Tool UI
function WeatherToolUI({ location, temperature, condition }) {
  return (
    <div className="flex items-center gap-3 rounded-lg border p-3">
      <WeatherIcon condition={condition} />
      <div>
        <div className="text-xs text-muted-foreground">{location}</div>
        <div className="text-lg font-medium">{temperature}°F</div>
      </div>
    </div>
  );
}

// Use in ToolGroup
<ToolGroupRoot variant="outline">
  <ToolGroupTrigger count={3} />
  <ToolGroupContent>
    <WeatherToolUI location="New York" temperature={65} condition="Cloudy" />
    <WeatherToolUI location="London" temperature={55} condition="Rainy" />
    <SearchToolUI query="best restaurants" results={24} />
  </ToolGroupContent>
</ToolGroupRoot>

Composable API

All sub-components are exported for custom layouts:

ComponentDescription
ToolGroup.RootCollapsible container with scroll lock and variants
ToolGroup.TriggerHeader with tool count, shimmer animation, and chevron
ToolGroup.ContentAnimated collapsible content wrapper
import {
  ToolGroup,
  ToolGroupRoot,
  ToolGroupTrigger,
  ToolGroupContent,
} from "@/components/assistant-ui/tool-group";

// Compound component syntax
<ToolGroup.Root variant="outline" defaultOpen>
  <ToolGroup.Trigger count={3} active={false} />
  <ToolGroup.Content>
    {/* Any tool UI components - custom or ToolFallback */}
  </ToolGroup.Content>
</ToolGroup.Root>

API Reference

ToolGroupRoot

ToolGroupRootProps
variant: "default" | "outline" | "muted"= "default"

Visual variant of the tool group container.

open?: boolean

Controlled open state.

onOpenChange?: (open: boolean) => void

Callback when open state changes.

defaultOpen: boolean= false

Initial open state for uncontrolled usage.

ToolGroupTrigger

ToolGroupTriggerProps
countrequired: number

Number of tool calls to display in the label.

active: boolean= false

Shows loading spinner and shimmer animation when true.

ToolGroup (Default Export)

ToolGroupProps
startIndexrequired: number

The index of the first tool call in the group.

endIndexrequired: number

The index of the last tool call in the group.

childrenrequired: ReactNode

The rendered tool call components.

  • ToolFallback - Default UI for tools without custom renderers
  • PartGrouping - Advanced message part grouping (experimental)