Commerce
Order summary
Subtotal, discounts, shipping, tax and total for a cart or checkout, collapsible on a phone.
- Built on
<dl><details>::details-contentContainer queriesIntl.NumberFormat<data>- Client JavaScript
- None
- Works without React
- Yes, as HTML and CSS
- Source, gzipped
- 3.2 kB
- Built from
- Icon
- Subtotal
- $124.00
- Code SPRING10
- Discount, minus $12.40
- Shipping
- Free
- Total
- $111.60
Code
import { OrderSummary } from "@/components/equip/order-summary";
export default function Demo() {
return (
<OrderSummary
style={{ width: 224 }}
subtotal={124}
discounts={[{ label: "Code SPRING10", amount: 12.4 }]}
shipping="free"
/>
);
}HTMLworks in any framework, with the part's CSS
<div style="width:224px" class="eq-order-summary">
<div class="eq-order-summary-body">
<dl class="eq-order-summary-list">
<div class="eq-order-summary-row" data-kind="subtotal">
<dt class="eq-order-summary-label">Subtotal</dt>
<dd class="eq-order-summary-value">
<data value="124">$124.00</data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="discount">
<dt class="eq-order-summary-label"><svg aria-hidden="true" focusable="false" class="eq-icon eq-order-summary-tag" data-size="s" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h7.5l8.5 8.5-7.5 7.5L4 11.5z" /><path d="M7.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0 -3 0" /></svg>Code SPRING10</dt>
<dd class="eq-order-summary-value">
<data value="-12.4"><span aria-hidden="true">-$12.40</span><span class="eq-order-summary-hidden">Discount, minus $12.40</span></data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="shipping">
<dt class="eq-order-summary-label">Shipping</dt>
<dd class="eq-order-summary-value">
<span class="eq-order-summary-free">Free</span>
</dd>
</div>
</dl>
<dl class="eq-order-summary-totals">
<div class="eq-order-summary-row" data-kind="total">
<dt class="eq-order-summary-label">Total</dt>
<dd class="eq-order-summary-value">
<data value="111.6">$111.60</data>
</dd>
</div>
</dl>
</div>
</div>Examples
Checkout sidebar
Discounts read as "Discount, minus $18.40", and the total is worked out from the rows unless you pass one.
Order summary
- Subtotal (3 items)
- $184.00
- Code SPRING10
- Discount, minus $18.40
- Member price
- Discount, minus $5.00
- Shipping
- $6.95
- Estimated tax
- $13.71
- Total
- $181.26
Code
import { OrderSummary } from "@/components/equip/order-summary";
import { Button } from "@/components/equip/button";
export default function Example() {
return (
<div
style={{
width: "100%",
maxWidth: 340,
boxSizing: "border-box",
padding: 20,
border: "1px solid var(--eq-line)",
borderRadius: "var(--eq-radius-l)",
background: "var(--eq-surface)",
display: "grid",
gap: 16,
}}
>
<OrderSummary
title="Order summary"
itemCount={3}
subtotal={184}
discounts={[
{ label: "Code SPRING10", amount: 18.4 },
{ label: "Member price", amount: 5 },
]}
shipping={6.95}
tax={13.71}
taxLabel="Estimated tax"
/>
<Button variant="accent" size="l" style={{ width: "100%" }}>
Place order
</Button>
</div>
);
}HTMLworks in any framework, with the part's CSS
<div style="width:100%;max-width:340px;box-sizing:border-box;padding:20px;border:1px solid var(--eq-line);border-radius:var(--eq-radius-l);background:var(--eq-surface);display:grid;gap:16px">
<div class="eq-order-summary">
<h2 class="eq-order-summary-title">Order summary</h2>
<div class="eq-order-summary-body">
<dl class="eq-order-summary-list">
<div class="eq-order-summary-row" data-kind="subtotal">
<dt class="eq-order-summary-label">Subtotal<span class="eq-order-summary-count"> (3 items)</span></dt>
<dd class="eq-order-summary-value">
<data value="184">$184.00</data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="discount">
<dt class="eq-order-summary-label"><svg aria-hidden="true" focusable="false" class="eq-icon eq-order-summary-tag" data-size="s" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h7.5l8.5 8.5-7.5 7.5L4 11.5z" /><path d="M7.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0 -3 0" /></svg>Code SPRING10</dt>
<dd class="eq-order-summary-value">
<data value="-18.4"><span aria-hidden="true">-$18.40</span><span class="eq-order-summary-hidden">Discount, minus $18.40</span></data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="discount">
<dt class="eq-order-summary-label"><svg aria-hidden="true" focusable="false" class="eq-icon eq-order-summary-tag" data-size="s" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h7.5l8.5 8.5-7.5 7.5L4 11.5z" /><path d="M7.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0 -3 0" /></svg>Member price</dt>
<dd class="eq-order-summary-value">
<data value="-5"><span aria-hidden="true">-$5.00</span><span class="eq-order-summary-hidden">Discount, minus $5.00</span></data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="shipping">
<dt class="eq-order-summary-label">Shipping</dt>
<dd class="eq-order-summary-value">
<data value="6.95">$6.95</data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="tax">
<dt class="eq-order-summary-label">Estimated tax</dt>
<dd class="eq-order-summary-value">
<data value="13.71">$13.71</data>
</dd>
</div>
</dl>
<dl class="eq-order-summary-totals">
<div class="eq-order-summary-row" data-kind="total">
<dt class="eq-order-summary-label">Total</dt>
<dd class="eq-order-summary-value">
<data value="181.26">$181.26</data>
</dd>
</div>
</dl>
</div>
</div>
<button style="width:100%" type="button" class="eq-button" data-variant="accent" data-size="l">
<span class="eq-button-label">Place order</span>
</button>
</div>Collapsible on a phone
Below 30rem the rows sit behind a native disclosure that shows the total; with "auto" a wider container shows them plainly.
Show order summaryHide order summary$90.38
- Subtotal (2 items)
- $98.00
- Code WELCOME15
- Discount, minus $14.70
- Shipping
- Calculated at the next step
- Estimated tax
- $7.08
- Total
- $90.38
Code
import { OrderSummary } from "@/components/equip/order-summary";
export default function Example() {
return (
<div style={{ width: "100%", maxWidth: 320, padding: 12, boxSizing: "border-box", border: "1px solid var(--eq-line)", borderRadius: "var(--eq-radius-m)" }}>
<OrderSummary
collapsible="auto"
itemCount={2}
subtotal={98}
discounts={[{ label: "Code WELCOME15", amount: 14.7 }]}
shipping={null}
tax={7.08}
taxLabel="Estimated tax"
/>
</div>
);
}HTMLworks in any framework, with the part's CSS
<div style="width:100%;max-width:320px;padding:12px;box-sizing:border-box;border:1px solid var(--eq-line);border-radius:var(--eq-radius-m)">
<div class="eq-order-summary" data-collapsible="auto">
<details class="eq-order-summary-disclosure">
<summary class="eq-order-summary-toggle"><span class="eq-order-summary-toggle-label"><span class="eq-order-summary-show">Show order summary</span><span class="eq-order-summary-hide">Hide order summary</span></span><svg aria-hidden="true" focusable="false" class="eq-icon eq-order-summary-chevron" data-size="s" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M5.5 9 12 15.5 18.5 9" /></svg><data class="eq-order-summary-toggle-total" value="90.38">$90.38</data></summary>
<div class="eq-order-summary-body">
<dl class="eq-order-summary-list">
<div class="eq-order-summary-row" data-kind="subtotal">
<dt class="eq-order-summary-label">Subtotal<span class="eq-order-summary-count"> (2 items)</span></dt>
<dd class="eq-order-summary-value">
<data value="98">$98.00</data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="discount">
<dt class="eq-order-summary-label"><svg aria-hidden="true" focusable="false" class="eq-icon eq-order-summary-tag" data-size="s" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h7.5l8.5 8.5-7.5 7.5L4 11.5z" /><path d="M7.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0 -3 0" /></svg>Code WELCOME15</dt>
<dd class="eq-order-summary-value">
<data value="-14.7"><span aria-hidden="true">-$14.70</span><span class="eq-order-summary-hidden">Discount, minus $14.70</span></data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="shipping">
<dt class="eq-order-summary-label">Shipping</dt>
<dd class="eq-order-summary-value">
<span class="eq-order-summary-pending">Calculated at the next step</span>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="tax">
<dt class="eq-order-summary-label">Estimated tax</dt>
<dd class="eq-order-summary-value">
<data value="7.08">$7.08</data>
</dd>
</div>
</dl>
<dl class="eq-order-summary-totals">
<div class="eq-order-summary-row" data-kind="total">
<dt class="eq-order-summary-label">Total</dt>
<dd class="eq-order-summary-value">
<data value="90.38">$90.38</data>
</dd>
</div>
</dl>
</div>
</details>
</div>
</div>Euros with VAT included
taxMode="included" keeps the VAT out of the sum and states it under the total, as European prices show it.
- Subtotal (2 items)
- 149,90 €
- Code HERBST20
- Discount, minus 29,98 €
- Shipping
- 4,90 €
- Total
- 124,82 €
- Includes 19% VAT
- 19,93 €
Code
import { OrderSummary } from "@/components/equip/order-summary";
export default function Example() {
return (
<OrderSummary
style={{ maxWidth: 340 }}
currency="EUR"
locale="de-DE"
itemCount={2}
subtotal={149.9}
discounts={[{ label: "Code HERBST20", amount: 29.98 }]}
shipping={4.9}
tax={19.93}
taxMode="included"
taxLabel="Includes 19% VAT"
/>
);
}HTMLworks in any framework, with the part's CSS
<div style="max-width:340px" class="eq-order-summary">
<div class="eq-order-summary-body">
<dl class="eq-order-summary-list">
<div class="eq-order-summary-row" data-kind="subtotal">
<dt class="eq-order-summary-label">Subtotal<span class="eq-order-summary-count"> (2 items)</span></dt>
<dd class="eq-order-summary-value">
<data value="149.9">149,90 €</data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="discount">
<dt class="eq-order-summary-label"><svg aria-hidden="true" focusable="false" class="eq-icon eq-order-summary-tag" data-size="s" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h7.5l8.5 8.5-7.5 7.5L4 11.5z" /><path d="M7.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0 -3 0" /></svg>Code HERBST20</dt>
<dd class="eq-order-summary-value">
<data value="-29.98"><span aria-hidden="true">-29,98 €</span><span class="eq-order-summary-hidden">Discount, minus 29,98 €</span></data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="shipping">
<dt class="eq-order-summary-label">Shipping</dt>
<dd class="eq-order-summary-value">
<data value="4.9">4,90 €</data>
</dd>
</div>
</dl>
<dl class="eq-order-summary-totals">
<div class="eq-order-summary-row" data-kind="total">
<dt class="eq-order-summary-label">Total</dt>
<dd class="eq-order-summary-value">
<data value="124.82000000000001">124,82 €</data>
</dd>
</div>
<div class="eq-order-summary-row" data-kind="included">
<dt class="eq-order-summary-label">Includes 19% VAT</dt>
<dd class="eq-order-summary-value">
<data value="19.93">19,93 €</data>
</dd>
</div>
</dl>
</div>
</div>Props
| Prop | Type | Default | What it does |
|---|---|---|---|
subtotal | number | none | Sum of the lines before discounts, in major units. |
discounts | { label: string; amount: number }[] | [] | Each a row such as "Code SPRING10", with a positive amount shown as a minus and read as "Discount, minus". |
shipping | number | "free" | null | none | An amount; "free" or 0 for Free; null for "Calculated at the next step". Leave out to hide the row. |
tax | number | none | Tax amount. Leave out to hide the row. |
taxLabel | string | "Tax" or "Includes tax" | Label of the tax row, such as "Estimated tax" or "Includes 19% VAT". |
taxMode | "added" | "included" | "added" | added sums tax into the total; included states it under the total without adding it. |
total | number | none | Replaces the total worked out from the rows. |
itemCount | number | none | Adds "(3 items)" to the subtotal label. |
currency | string | "USD" | ISO 4217 currency code. |
locale | string | "en-US" | Sets the symbol position, separators and grouping. |
title | ReactNode | none | A heading above the rows, such as "Order summary". |
headingLevel | 2 | 3 | 4 | 2 | The title's heading level. |
collapsible | boolean | "auto" | false | true puts the rows behind a "Show order summary" disclosure with the total; "auto" only below a 30rem container. |
defaultOpen | boolean | false | Whether the disclosure starts open. |
children | ReactNode | none | Placed above the total, such as a coupon field. |
...rest | Omit<ComponentProps<"div">, "title"> | none | Every native div attribute, applied to the root. |
Anatomy
| root | .eq-order-summary | The size container; data-collapsible is true or auto when set. |
|---|---|---|
| title | .eq-order-summary-title | |
| disclosure | .eq-order-summary-disclosure | A native <details>, only when collapsible. |
| toggle | .eq-order-summary-toggle | The <summary>: label, chevron and total. |
| toggle label | .eq-order-summary-toggle-label | |
| show text | .eq-order-summary-show | Shown while closed. |
| hide text | .eq-order-summary-hide | Shown while open. |
| chevron | .eq-order-summary-chevron | |
| toggle total | .eq-order-summary-toggle-total | |
| body | .eq-order-summary-body | |
| list | .eq-order-summary-list | A <dl> of subtotal, discounts, shipping and tax. |
| row | .eq-order-summary-row | A <div> holding one <dt> and <dd>; data-kind names the row. |
| label | .eq-order-summary-label | |
| value | .eq-order-summary-value | End-aligned, tabular figures. |
| count | .eq-order-summary-count | |
| tag | .eq-order-summary-tag | The tag icon before a discount label. |
| free | .eq-order-summary-free | |
| pending | .eq-order-summary-pending | Shipping not worked out yet. |
| extra | .eq-order-summary-extra | Holds children, above the total. |
| totals | .eq-order-summary-totals | A second <dl> with the total and any included tax, under a rule. |
| hidden text | .eq-order-summary-hidden | Words for screen readers only. |
Keyboard
| EnterSpace | On the disclosure toggle, shows or hides the rows. |
|---|
Notes
- Renders on the server with no client JavaScript; the disclosure is a native <details>.
- A <dl> rather than a table: each row is a name and a value, and screen readers read label then amount without table navigation.
- Every amount uses the currency's own fraction digits, so $124.00 and $12.40 line up in the end-aligned column.
- Discounts show the locale's minus sign and read as "Discount, minus $12.40"; the colour is never the only cue.
- CSS cannot open a <details> by width, so "auto" keeps the disclosure in the DOM and, in a wide container, hides the toggle and shows the rows through ::details-content.
- The toggle reads "Show order summary" or "Hide order summary" with the total, and the native element reports expanded or collapsed.
- The total is the subtotal less discounts plus shipping and added tax, never below zero; pass total when your server has the final figure.
- ::details-content is in Chrome 131, Safari 18.4 and Firefox 143. Elsewhere collapsible="auto" stays a disclosure at every width, so the rows are still one click away.
Source
Two files, and they are the whole part. Open either to read it, copy it straight from its bar, or add the part to your loadout and install it with everything else you picked.
components/equip/order-summary.tsx154 lines
import type { ComponentProps, ReactNode } from "react";
import { Icon } from "./icon";
import "./order-summary.css";
export type OrderSummaryDiscount = {
/** Says where it comes from, such as "Code SPRING10" or "Member price". */
label: string;
/** The amount taken off, as a positive number in major units. */
amount: number;
};
export type OrderSummaryProps = Omit<ComponentProps<"div">, "title"> & {
subtotal: number;
discounts?: OrderSummaryDiscount[];
/** A number, "free" (or 0) for Free, null for "Calculated at the next step". Leave out to hide the row. */
shipping?: number | "free" | null;
/** Tax amount. Leave out to hide the row. */
tax?: number;
/** Label of the tax row, such as "Estimated tax" or "Includes 19% VAT". */
taxLabel?: string;
/** "added" puts tax on top of the total; "included" shows it as a note under the total. */
taxMode?: "added" | "included";
/** Replaces the total worked out from the lines above. */
total?: number;
/** Adds "(3 items)" to the subtotal label. */
itemCount?: number;
/** ISO 4217 code. */
currency?: string;
locale?: string;
/** A heading above the rows, such as "Order summary". */
title?: ReactNode;
headingLevel?: 2 | 3 | 4;
/** true wraps the rows in a disclosure; "auto" does so only in a narrow container, where supported. */
collapsible?: boolean | "auto";
/** Whether the disclosure starts open. */
defaultOpen?: boolean;
/** Placed above the total, such as a CouponField. */
children?: ReactNode;
};
export function OrderSummary({
subtotal,
discounts = [],
shipping,
tax,
taxLabel,
taxMode = "added",
total,
itemCount,
currency = "USD",
locale = "en-US",
title,
headingLevel = 2,
collapsible = false,
defaultOpen = false,
children,
className,
...rest
}: OrderSummaryProps) {
const money = new Intl.NumberFormat(locale, { style: "currency", currency });
const off = discounts.reduce((sum, d) => sum + d.amount, 0);
const shippingCost = typeof shipping === "number" ? shipping : 0;
const taxAdded = taxMode === "added" && tax != null ? tax : 0;
const grand = total ?? Math.max(0, subtotal - off + shippingCost + taxAdded);
const Heading = `h${headingLevel}` as const;
const row = (kind: string, label: ReactNode, value: ReactNode, key?: string) => (
<div className="eq-order-summary-row" data-kind={kind} key={key}>
<dt className="eq-order-summary-label">{label}</dt>
<dd className="eq-order-summary-value">{value}</dd>
</div>
);
const amount = (n: number) => <data value={n}>{money.format(n)}</data>;
const rows = (
<>
<dl className="eq-order-summary-list">
{row(
"subtotal",
<>
Subtotal
{itemCount != null && (
<span className="eq-order-summary-count">
{" "}
({itemCount} {itemCount === 1 ? "item" : "items"})
</span>
)}
</>,
amount(subtotal),
)}
{discounts.map((d, i) =>
row(
"discount",
<>
<Icon name="tag" size="s" className="eq-order-summary-tag" />
{d.label}
</>,
<data value={-d.amount}>
<span aria-hidden="true">{money.format(-d.amount)}</span>
<span className="eq-order-summary-hidden">Discount, minus {money.format(d.amount)}</span>
</data>,
`${d.label}-${i}`,
),
)}
{shipping !== undefined &&
row(
"shipping",
"Shipping",
shipping === null ? (
<span className="eq-order-summary-pending">Calculated at the next step</span>
) : shipping === "free" || shipping === 0 ? (
<span className="eq-order-summary-free">Free</span>
) : (
amount(shipping)
),
)}
{tax != null && taxMode === "added" && row("tax", taxLabel ?? "Tax", amount(tax))}
</dl>
{children != null && <div className="eq-order-summary-extra">{children}</div>}
<dl className="eq-order-summary-totals">
{row("total", "Total", amount(grand))}
{tax != null && taxMode === "included" && row("included", taxLabel ?? "Includes tax", amount(tax))}
</dl>
</>
);
return (
<div
{...rest}
className={["eq-order-summary", className].filter(Boolean).join(" ")}
data-collapsible={collapsible === false ? undefined : String(collapsible)}
>
{title != null && <Heading className="eq-order-summary-title">{title}</Heading>}
{collapsible === false ? (
<div className="eq-order-summary-body">{rows}</div>
) : (
<details className="eq-order-summary-disclosure" open={defaultOpen || undefined}>
<summary className="eq-order-summary-toggle">
<span className="eq-order-summary-toggle-label">
<span className="eq-order-summary-show">Show order summary</span>
<span className="eq-order-summary-hide">Hide order summary</span>
</span>
<Icon name="chevron-down" size="s" className="eq-order-summary-chevron" />
<data className="eq-order-summary-toggle-total" value={grand}>
{money.format(grand)}
</data>
</summary>
<div className="eq-order-summary-body">{rows}</div>
</details>
)}
</div>
);
}components/equip/order-summary.css221 lines
@layer equip {
.eq-order-summary {
container-type: inline-size;
box-sizing: border-box;
width: 100%;
color: var(--eq-ink);
font: var(--eq-weight) var(--eq-text-m) / 1.4 var(--eq-font);
}
.eq-order-summary-title {
margin: 0 0 var(--eq-space-3);
font-size: var(--eq-text-l);
font-weight: var(--eq-weight-strong);
line-height: 1.3;
}
.eq-order-summary-body {
display: flex;
flex-direction: column;
gap: var(--eq-space-3);
}
.eq-order-summary-list,
.eq-order-summary-totals {
display: flex;
flex-direction: column;
gap: var(--eq-space-2);
margin: 0;
}
/* Label at the start, amount at the end; the amount never wraps, the label may. */
.eq-order-summary-row {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: var(--eq-space-3);
}
.eq-order-summary-label {
display: inline-flex;
align-items: baseline;
gap: var(--eq-space-1);
min-width: 0;
color: var(--eq-ink-2);
}
.eq-order-summary-value {
margin: 0;
margin-inline-start: auto;
font-variant-numeric: tabular-nums;
text-align: end;
white-space: nowrap;
}
.eq-order-summary-count {
color: var(--eq-ink-3);
}
.eq-order-summary-tag {
align-self: center;
color: var(--eq-ink-3);
}
.eq-order-summary-row[data-kind="discount"] .eq-order-summary-value {
color: var(--eq-ok);
}
.eq-order-summary-free {
color: var(--eq-ok);
font-weight: var(--eq-weight-strong);
}
.eq-order-summary-pending {
color: var(--eq-ink-2);
font-size: var(--eq-text-s);
white-space: normal;
}
.eq-order-summary-extra {
padding-block: var(--eq-space-1);
}
/* The total stands apart: a rule above, a larger strong figure. */
.eq-order-summary-totals {
padding-top: var(--eq-space-3);
border-top: 1px solid var(--eq-line-strong);
}
.eq-order-summary-row[data-kind="total"] .eq-order-summary-label {
color: var(--eq-ink);
font-weight: var(--eq-weight-strong);
}
.eq-order-summary-row[data-kind="total"] .eq-order-summary-value {
font-size: var(--eq-text-l);
font-weight: var(--eq-weight-strong);
letter-spacing: -0.01em;
}
@container (width >= 20rem) {
.eq-order-summary-row[data-kind="total"] .eq-order-summary-value {
font-size: calc(var(--eq-text-l) * 1.25);
}
}
.eq-order-summary-row[data-kind="included"] {
margin-top: calc(-1 * var(--eq-space-1));
font-size: var(--eq-text-s);
}
.eq-order-summary-row[data-kind="included"] .eq-order-summary-value {
color: var(--eq-ink-2);
}
/* The disclosure: "Show order summary" and the total, on one row. */
.eq-order-summary-toggle {
display: flex;
align-items: center;
gap: var(--eq-space-1);
min-height: var(--eq-h-m);
margin-inline: calc(-1 * var(--eq-space-2));
padding-inline: var(--eq-space-2);
border-radius: var(--eq-radius-s);
list-style: none;
cursor: pointer;
user-select: none;
transition: background-color var(--eq-dur) var(--eq-ease);
}
.eq-order-summary-toggle::-webkit-details-marker {
display: none;
}
@media (hover: hover) {
.eq-order-summary-toggle:hover {
background: var(--eq-tint);
}
}
.eq-order-summary-toggle:focus-visible {
outline: 2px solid var(--eq-focus);
outline-offset: 2px;
}
.eq-order-summary-toggle-label {
font-weight: var(--eq-weight-strong);
}
.eq-order-summary-disclosure[open] .eq-order-summary-show,
.eq-order-summary-disclosure:not([open]) .eq-order-summary-hide {
display: none;
}
.eq-order-summary-chevron {
color: var(--eq-ink-2);
transition: rotate var(--eq-dur-move) var(--eq-spring);
}
.eq-order-summary-disclosure[open] .eq-order-summary-chevron {
rotate: 180deg;
}
.eq-order-summary-toggle-total {
margin-inline-start: auto;
font-weight: var(--eq-weight-strong);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
/* Open: the total already sits at the bottom, so the toggle drops its copy. */
.eq-order-summary-disclosure[open] .eq-order-summary-toggle-total {
opacity: 0;
}
.eq-order-summary-disclosure .eq-order-summary-body {
padding-top: var(--eq-space-3);
}
.eq-order-summary-disclosure[open] .eq-order-summary-body {
transition:
opacity var(--eq-dur-move) var(--eq-spring),
translate var(--eq-dur-move) var(--eq-spring);
}
@starting-style {
.eq-order-summary-disclosure[open] .eq-order-summary-body {
opacity: 0;
translate: 0 -4px;
}
}
/* "auto": in a wide container the rows are always shown and the toggle goes. Only where
::details-content is supported, so a closed summary is never stuck shut. */
@supports selector(::details-content) {
@container (width >= 30rem) {
.eq-order-summary[data-collapsible="auto"] .eq-order-summary-toggle {
display: none;
}
.eq-order-summary[data-collapsible="auto"] .eq-order-summary-disclosure::details-content {
content-visibility: visible;
}
.eq-order-summary[data-collapsible="auto"] .eq-order-summary-disclosure .eq-order-summary-body {
padding-top: 0;
}
}
}
.eq-order-summary-hidden {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
}