Order Summary

The checkout and cart order read-out. One composable card that stacks line items, a promo-code band and a totals breakdown, with every price on tabular-nums so the column never jitters.

Order summary

4 items
  • Retro Sneakers2
    Retro Sneakers
    Size 10 · Red
    $64.00
  • Chrono Watch
    Chrono Watch
    40mm · Leather
    $78.00
  • Studio Headphones
    Studio Headphones
    Black · Over-ear
    $149.00
Subtotal
$291.00
Shipping
Free
Estimated tax
$23.28
Discount (WELCOME10)
-$29.10
Total
$285.18

Taxes and shipping calculated at checkout.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add order-summary

Usage#

usage.tsxTSX
import {  OrderSummary,  OrderSummaryHeader,  OrderSummaryTitle,  OrderSummaryItems,  OrderSummaryItem,  OrderSummaryItemThumbnail,  OrderSummaryItemContent,  OrderSummaryItemName,  OrderSummaryItemOptions,  OrderSummaryItemPrice,  OrderSummaryPromo,  OrderSummaryTotals,  OrderSummaryRow,  OrderSummaryTotal,  OrderSummaryFooter,} from "@/components/ui/order-summary"export function Example() {  return (    <OrderSummary>      <OrderSummaryItems>        <OrderSummaryItem>          <OrderSummaryItemThumbnail count={2}>            <img src="/sneakers.jpg" alt="Retro Sneakers" />          </OrderSummaryItemThumbnail>          <OrderSummaryItemContent>            <OrderSummaryItemName>Retro Sneakers</OrderSummaryItemName>            <OrderSummaryItemOptions>Size 10 · Red</OrderSummaryItemOptions>          </OrderSummaryItemContent>          <OrderSummaryItemPrice>$64.00</OrderSummaryItemPrice>        </OrderSummaryItem>      </OrderSummaryItems>      <OrderSummaryTotals>        <OrderSummaryRow label="Subtotal">$64.00</OrderSummaryRow>        <OrderSummaryTotal label="Total">$64.00</OrderSummaryTotal>      </OrderSummaryTotals>    </OrderSummary>  )}

Anatomy#

OrderSummary is a multi-part component: one tv recipe whose slots flow to every named part through React Context. Compose only the bands you need, in any order. There are no internal dividers or boxing: the bands and the line items are simply set apart by whitespace (the house minimal style), so the summary reads clean on any surface. The card variant adds an outer border and insets the content with padding; plain sits flush.

anatomy.tsxTSX
<OrderSummary>            {/* the card shell */}  <OrderSummaryHeader>     {/* title + item-count Badge */}    <OrderSummaryTitle />  </OrderSummaryHeader>  <OrderSummaryItems>      {/* the <ul> of line items */}    <OrderSummaryItem>     {/* one <li> row */}      <OrderSummaryItemThumbnail count={2} />      <OrderSummaryItemContent>        <OrderSummaryItemName />        <OrderSummaryItemOptions />      </OrderSummaryItemContent>      <OrderSummaryItemPrice />    </OrderSummaryItem>  </OrderSummaryItems>  <OrderSummaryPromo />     {/* slot for an InputGroup */}  <OrderSummaryTotals>      {/* the <dl> breakdown */}    <OrderSummaryRow label="Subtotal">…</OrderSummaryRow>    <OrderSummaryTotal label="Total">…</OrderSummaryTotal>  </OrderSummaryTotals>  <OrderSummaryFooter />    {/* slot for the checkout CTA */}</OrderSummary>

Line items#

Each OrderSummaryItem is a <li> laying out a thumbnail, the name + options, and the line price. The thumbnail holds an <img> (auto object-cover with the DS image-outline) or a Phosphor glyph, and its count prop drops a quantity pill on the corner. The name truncates rather than shoving the price off the row, and the price is tabular-nums so the column stays aligned.

Your cart
4 items
  • Retro Sneakers2
    Retro Sneakers
    Size 10 · Red
    $64.00
  • Chrono Watch
    Chrono Watch
    40mm · Leather
    $78.00
  • Studio Headphones
    Studio Headphones
    Black · Over-ear
    $149.00

Shopping cart#

Compose OrderSummaryItemActions after the price to turn the read-out into a shopping cart. It holds OrderSummaryItemQuantity (the canonical NumberInput in its compact inline − value + form) and OrderSummaryItemRemove (the canonical Button in its quiet destructiveGhost trash form). Wire their onValueChange / onClick to your cart state; here the line prices and the subtotal recompute live. Removing a row sets leaving on its OrderSummaryItem so it collapses and drifts out before it's dropped from state (the rows below glide up, no jump); clearing the cart shows the empty state.

Summary

Review your items carefully before proceeding to checkout.

  • Retro Sneakers
    Retro Sneakers
    Size 10 · Red
    $64.00
  • Chrono Watch
    Chrono Watch
    40mm · Leather
    $78.00
  • Studio Headphones
    Studio Headphones
    Black · Over-ear
    $149.00
Subtotal
$291.00
Shipping
Free
Total
$291.00

Totals & tones#

OrderSummaryTotals renders a semantic <dl>. Each OrderSummaryRow takes a label (the <dt>) and its value as children (the <dd>). The tone prop accents the value: discount greens a credit, muted softens a "Free" or "calculated later" placeholder. OrderSummaryTotal is the emphasized grand total, set apart from the rows by extra whitespace.

Subtotal
$291.00
Shipping
Free
Estimated tax
$23.28
Store credit
-$15.00
Total due
$299.28

Promo code#

OrderSummaryPromo is a band you fill with the canonical InputGroup — a field joined to an Apply button in one seamless shell. Nothing is re-styled inline; the summary composes the real controls, so the promo row stays in lockstep with the input family.

The band imposes the big control tier on what you put in it (size="lg", 40px), the way Form does for its fields: a promo code is a real form control, not a table filter, so it matches the Checkout button under the totals instead of shrinking to the ambient density. Pass size for a different tier; a size on the control itself still wins.

promo.tsxTSX
<OrderSummaryPromo>  <InputGroup>    <InputRoot>      <InputField placeholder="Promo code" />    </InputRoot>    <Button variant="secondary">Apply</Button>  </InputGroup></OrderSummaryPromo>

Variants & density#

The default card variant is the bordered checkout sidebar. plain drops the frame so the bands sit flush on whatever surface holds them — a page column or a Drawer. Density is Koala's spacing axis: comfortable (the default) suits a checkout page; compact tightens the padding and shrinks the thumbnails for a mini-cart. Set it per instance or once on a DensityProvider.

  • Retro Sneakers2
    Retro Sneakers
    Size 10 · Red
    $64.00
  • Chrono Watch
    Chrono Watch
    40mm · Leather
    $78.00
Subtotal
$142.00
Shipping
Free
Total
$142.00

API reference#

OrderSummary

The card shell (a <section>). Props: variant ("card" | "plain", default "card"), density ("comfortable" | "compact"), asChild, plus all <section> props. Density resolves prop > nearest DensityProvider > "comfortable".

OrderSummaryHeader / OrderSummaryTitle

The title band (a justify-between row) and its title. OrderSummaryTitle takes asChild to render a real heading (<h2>/<h3>).

OrderSummaryItems / OrderSummaryItem

The line-item <ul> and each <li> row. Rows stack with whitespace (the density-scaled items gap), no dividers.

OrderSummaryItemThumbnail

The product tile. Holds an <img> (auto object-cover + image outline), a Phosphor glyph, or nothing. Prop count renders a quantity pill on the corner.

OrderSummaryItemContent / Name / Options / Price

The content column (name truncates), the muted options line, and the trailing line price (tabular-nums).

OrderSummaryPromo

A band; fill it with an InputGroup (promo field + Apply button). Takes size (sm · md · lg, default lg), the control height it imposes on its children.

OrderSummaryTotals / OrderSummaryRow / OrderSummaryTotal

The totals <dl>. OrderSummaryRow takes label (<dt>), its value as children (<dd>), and tone ("default" | "discount" | "muted"). OrderSummaryTotal is the emphasized grand total.

OrderSummaryFooter

A band for the checkout Button and a trust note.

FAQ#

Because that's what they are semantically. The items are a list of products (OrderSummaryItems renders a <ul> of <li> rows), and the totals are label/value pairs (OrderSummaryTotals renders a <dl> with <dt> labels and <dd> values). Screen readers announce them correctly with no extra ARIA.