Tabs

Split a reply into a few parallel views, each holding other components.

Primitive

≈ 920 tokens per use (tool 351 · guidance 166 · typical payload 403)How token costs are estimated

Example: Tabs

Plan our long weekend in Lisbon.

Lisbon, long weekend

Food, viewpoints and a beach afternoon.

Dates
Fri 14 – Mon 17 Nov
Travelers
Two adults
Stay
Alfama, 3 nights
Budget
About €1,400

When to use

  • The reply splits into 2–5 parallel views of the same subject the user will switch between, like Overview, Packing and Budget for a trip.

When not to use

  • The content is a sequence the user moves through. Use a guided flow.
  • There's only one view, or the views are short enough to stack.
  • Something the user must see would end up hidden in a later tab.

How it works

Each tab holds 1–3 other GenUI components, named by their catalog key and given their own props:

{
  "tabs": [
    { "id": "overview", "label": "Overview", "children": [{ "component": "show_summary", "props": { "title": "…", "facts": [] } }] },
    { "id": "budget", "label": "Budget", "children": [{ "component": "build_calculator", "props": { "…": "…" } }] }
  ]
}
  • Layouts render through the Renderer. It passes them a renderChild function, so children come from the same catalog as everything else.
  • Every panel stays mounted (just hidden), so a child's state, like ticked checklist steps, survives switching tabs.
  • One level of nesting. A tab may hold columns, a grid or a split, and no deeper. A child's props may bind to a sibling's result.
  • One tool call, one result per child. A layout is a single tool call. Each interactive child's result comes back as { child: "budget.0", result: { … } }, and it's restored the same way when the conversation reloads.

How the agent should use it

  • The first (or defaultTab) tab holds the main answer.
  • Keep labels to one or two words.
  • Give each tab one clear purpose.

Installation

npx shadcn@latest add https://your-site.com/r/layout-tabs.json

Usage

Register it in your catalog next to the components it may contain:

lib/genui-catalog.ts
import { LayoutTabs } from "@/components/genui/layout-tabs"

export const catalog = {
  show_tabs: LayoutTabs,
  show_summary: SummaryCard,
  show_checklist: Checklist,
  build_calculator: Calculator,
} satisfies GenUICatalog
app/api/chat/route.ts
import { tool } from "ai"
import { layoutTabsTool } from "@/components/genui/layout-tabs.schema"

const tools = {
  [layoutTabsTool.name]: tool({
    description: layoutTabsTool.description,
    inputSchema: layoutTabsTool.inputSchema,
  }),
}

With LangGraph

Push it like any component, with ui.push({ name: "show_tabs", props: { toolCallId, ...args } }, { message }), and render it with the Renderer.

Schema

PropTypeNotes
tabs{ id, label, children }[]2–5 tabs. Labels up to 24 characters
tabs[].children{ component, props, id? }[]1–3 components
defaultTabstring?The tab to open first

Host props: status and className. renderChild is injected by the Renderer.

Source

On this page