Order Summary
- Subtotal
- $189.97
- Shipping
- Free
- Tax
- $16.62
- Total
- $206.59
import { OrderSummary } from "@/components/tool-ui/order-summary";export function Example() { return ( <OrderSummary id="order-summary-example" items={[ { id: "item-1", name: "Wireless Earbuds Pro", description: "Active noise cancellation", imageUrl: "https://example.com/earbuds.jpg", quantity: 1, unitPrice: 149.99, }, { id: "item-2", name: "USB-C Charging Cable", description: "2m braided", quantity: 2, unitPrice: 19.99, }, ]} pricing={{ subtotal: 189.97, tax: 16.62, shipping: 0, total: 206.59, currency: "USD", }} onResponseAction={(actionId) => { console.log("Action:", actionId); }} /> );}Prices formatted with Intl.NumberFormat for any currency code
Shows subtotal, tax, shipping, discounts, and total
Dims and shows confirmation after purchase is confirmed
Placeholder icon when product images aren't available
When decision is set, the component renders in a dimmed receipt state showing the confirmed order with order ID and timestamp.
#ORD-2024-8847 · Dec 15, 2024
<OrderSummary id="receipt-example" title="Order Confirmed" items={[...]} pricing={{...}} decision={{ action: "confirm", orderId: "ORD-2024-8847", confirmedAt: "2024-12-15T14:32:00Z", }}/>Use the discount and discountLabel fields in pricing to show promotional savings.
<OrderSummary id="discount-example" pricing={{ subtotal: 449.00, discount: 44.90, discountLabel: "SAVE10 (10% off)", tax: 35.92, shipping: 0, total: 440.02, currency: "USD", }} // .../>Copy components/tool-ui/order-summary and the shared directory into your project. The shared folder contains utilities used by all Tool UI components. The tool-ui directory should sit alongside your shadcn ui directory.
This component requires the following shadcn/ui components:
pnpm dlx shadcn@latest add button separator skeleton"use client";import { makeAssistantTool } from "@assistant-ui/react";import { OrderSummary, OrderSummaryErrorBoundary, parseSerializableOrderSummary, SerializableOrderSummarySchema, type SerializableOrderSummary, type OrderDecision,} from "@/components/tool-ui/order-summary";export const OrderSummaryTool = makeAssistantTool< SerializableOrderSummary, OrderDecision>({ toolName: "createOrder", description: "Display a purchase order for user confirmation", parameters: SerializableOrderSummarySchema, render: ({ args, result, addResult, toolCallId }) => { if (!args?.items?.length || !args?.pricing) return null; const data = parseSerializableOrderSummary({ ...args, id: args?.id ?? `order-${toolCallId}`, }); return ( <OrderSummaryErrorBoundary> {result !== undefined ? ( <OrderSummary {...data} decision={result} /> ) : ( <OrderSummary {...data} onResponseAction={(actionId) => { if (actionId === "confirm") { addResult({ action: "confirm", orderId: `ORD-${Date.now()}`, confirmedAt: new Date().toISOString(), }); } }} /> )} </OrderSummaryErrorBoundary> ); },});Mount <OrderSummaryTool /> under <AssistantRuntimeProvider> to register the tool and its UI.
Prop
Type
Prop
Type
Prop
Type
<article> with aria-labelledby pointing to the titlearia-busy="true" during loading statesalt="" since item names provide the descriptionimport { OrderSummary } from "@/components/tool-ui/order-summary";
export function Example() {
return (
<OrderSummary
id="order-summary-example"
items={[
{
id: "item-1",
name: "Wireless Earbuds Pro",
description: "Active noise cancellation",
imageUrl: "https://example.com/earbuds.jpg",
quantity: 1,
unitPrice: 149.99,
},
{
id: "item-2",
name: "USB-C Charging Cable",
description: "2m braided",
quantity: 2,
unitPrice: 19.99,
},
]}
pricing={{
subtotal: 189.97,
tax: 16.62,
shipping: 0,
total: 206.59,
currency: "USD",
}}
onResponseAction={(actionId) => {
console.log("Action:", actionId);
}}
/>
);
}<OrderSummary
id="receipt-example"
title="Order Confirmed"
items={[...]}
pricing={{...}}
decision={{
action: "confirm",
orderId: "ORD-2024-8847",
confirmedAt: "2024-12-15T14:32:00Z",
}}
/><OrderSummary
id="discount-example"
pricing={{
subtotal: 449.00,
discount: 44.90,
discountLabel: "SAVE10 (10% off)",
tax: 35.92,
shipping: 0,
total: 440.02,
currency: "USD",
}}
// ...
/>"use client";
import { makeAssistantTool } from "@assistant-ui/react";
import {
OrderSummary,
OrderSummaryErrorBoundary,
parseSerializableOrderSummary,
SerializableOrderSummarySchema,
type SerializableOrderSummary,
type OrderDecision,
} from "@/components/tool-ui/order-summary";
export const OrderSummaryTool = makeAssistantTool<
SerializableOrderSummary,
OrderDecision
>({
toolName: "createOrder",
description: "Display a purchase order for user confirmation",
parameters: SerializableOrderSummarySchema,
render: ({ args, result, addResult, toolCallId }) => {
if (!args?.items?.length || !args?.pricing) return null;
const data = parseSerializableOrderSummary({
...args,
id: args?.id ?? `order-${toolCallId}`,
});
return (
<OrderSummaryErrorBoundary>
{result !== undefined ? (
<OrderSummary {...data} decision={result} />
) : (
<OrderSummary
{...data}
onResponseAction={(actionId) => {
if (actionId === "confirm") {
addResult({
action: "confirm",
orderId: `ORD-${Date.now()}`,
confirmedAt: new Date().toISOString(),
});
}
}}
/>
)}
</OrderSummaryErrorBoundary>
);
},
});pnpm dlx shadcn@latest add button separator skeleton