Documents
tool-group
tool-group
Type
External
Status
Published
Created
Mar 17, 2026
Updated
May 5, 2026
Updated by
Dosu Bot
Source
View

import {
ToolGroupSample,
ToolGroupStreamingSample,
} from "@/components/docs/samples/tool-group";

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

Getting Started#

Add tool-group and tool-fallback#

<InstallCommand shadcn={["tool-group", "tool-fallback"]} />

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

Use it in your application#

Use MessagePrimitive.GroupedParts and return "group-tool" for tool-call parts. The group case wraps children; the tool-call leaf renders the resolved tool UI or your fallback.

import { MessagePrimitive } from "@assistant-ui/react";
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
import {
  ToolGroupContent,
  ToolGroupRoot,
  ToolGroupTrigger,
} from "@/components/assistant-ui/tool-group";

const AssistantMessage = () => {
  return (
    <MessagePrimitive.Root>
      <MessagePrimitive.GroupedParts
        groupBy={(part) => {
          if (part.type === "tool-call") return ["group-tool"];
          return null;
        }}
        {({ part, children }) => {
          switch (part.type) {
            case "group-tool":
              return (
                <ToolGroupRoot>
                  <ToolGroupTrigger
                    count={part.indices.length}
                    active={part.status.type === "running"}
                  />
                  <ToolGroupContent>{children}</ToolGroupContent>
                </ToolGroupRoot>
              );
            case "tool-call":
              return part.toolUI ?? <ToolFallback {...part} />;
            default:
              return null;
          }
        }}
      </MessagePrimitive.GroupedParts>
    </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
outlineRounded border (default)
ghostNo additional styling
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.

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#

<ParametersTable
type="ToolGroupRootProps"
parameters={[
{
name: "variant",
type: '"outline" | "ghost" | "muted"',
default: '"outline"',
description: "Visual variant of the tool group container.",
},
{
name: "open",
type: "boolean",
description: "Controlled open state.",
},
{
name: "onOpenChange",
type: "(open: boolean) => void",
description: "Callback when open state changes.",
},
{
name: "defaultOpen",
type: "boolean",
default: "false",
description: "Initial open state for uncontrolled usage.",
},
]}
/>

ToolGroupTrigger#

<ParametersTable
type="ToolGroupTriggerProps"
parameters={[
{
name: "count",
type: "number",
required: true,
description: "Number of tool calls to display in the label.",
},
{
name: "active",
type: "boolean",
default: "false",
description: "Shows loading spinner and shimmer animation when true.",
},
]}
/>

ToolGroup (Legacy Wrapper)#

ToolGroup is kept for existing code that still uses the deprecated components.ToolGroup prop on MessagePrimitive.Parts. Prefer composing ToolGroupRoot, ToolGroupTrigger, and ToolGroupContent inside MessagePrimitive.GroupedParts.

<ParametersTable
type="ToolGroupProps"
parameters={[
{
name: "startIndex",
type: "number",
required: true,
description: "The index of the first tool call in the group.",
},
{
name: "endIndex",
type: "number",
required: true,
description: "The index of the last tool call in the group.",
},
{
name: "children",
type: "ReactNode",
required: true,
description: "The rendered tool call components.",
},
]}
/>

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