Order table
An order list whose rows link to their orders, with the date, the customer, payment and fulfilment as two Badges with words, and the total. A server composition; it ships no JavaScript.
From Figma 05 Commerce, Order Row (7275:14091; the example table 7275:14114). Uses
Table, Avatar,
Badge, Inline and
NumberValue.
Examples
Recent orders
Figma 05's Order Row (7275:14091) as an order list. The order number is a stretched link, so the whole row is its hit area and the row is one Tab stop. Payment and fulfilment are two Badges with words, never colour alone. A server composition: it ships no JavaScript.
import type { JSX } from 'react';
import { Avatar } from '@nizivo/react/avatar';
import { Badge, type BadgeTone } from '@nizivo/react/badge';
import { Inline } from '@nizivo/react/inline';
import { NumberValue } from '@nizivo/react/number-value';
import { Table } from '@nizivo/react/table';
/** Money as the store's currency: Intl formats it, never string concatenation. */
const USD = { style: 'currency', currency: 'USD' } as const;
// An explicit locale and time zone, so the server and the browser print the same text.
const PLACED = new Intl.DateTimeFormat('en-US', {
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
timeZone: 'UTC',
});
type Payment = 'paid' | 'pending' | 'refunded';
type Fulfillment = 'fulfilled' | 'unfulfilled' | 'on-hold';
/** Each status's words and tone. The words carry the meaning; the tone only repeats it. */
const PAYMENT: Record<Payment, { label: string; tone: BadgeTone }> = {
paid: { label: 'Paid', tone: 'success' },
pending: { label: 'Pending', tone: 'warning' },
refunded: { label: 'Refunded', tone: 'neutral' },
};
const FULFILLMENT: Record<Fulfillment, { label: string; tone: BadgeTone }> = {
fulfilled: { label: 'Fulfilled', tone: 'success' },
unfulfilled: { label: 'Unfulfilled', tone: 'warning' },
'on-hold': { label: 'On hold', tone: 'neutral' },
};
interface Order {
number: string;
/** A UTC instant, as the server stores it. */
placed: string;
customer: string;
payment: Payment;
fulfillment: Fulfillment;
total: number;
}
const ORDERS: Order[] = [
{
number: '1042',
placed: '2026-10-14T09:12:00Z',
customer: 'Maya Lindqvist',
payment: 'paid',
fulfillment: 'unfulfilled',
total: 112,
},
{
number: '1041',
placed: '2026-10-14T08:47:00Z',
customer: 'Jonah Okafor',
payment: 'paid',
fulfillment: 'fulfilled',
total: 64,
},
{
number: '1040',
placed: '2026-10-13T17:05:00Z',
customer: 'Priya Raman',
payment: 'pending',
fulfillment: 'on-hold',
total: 238.5,
},
{
number: '1039',
placed: '2026-10-13T11:30:00Z',
customer: 'Leo Marchetti',
payment: 'refunded',
fulfillment: 'fulfilled',
total: 46,
},
];
export function OrderTableExample(): JSX.Element {
return (
<Table.Container label="Orders">
<Table.Root>
<Table.Caption visuallyHidden>Orders</Table.Caption>
<Table.Header>
<Table.Row>
<Table.Head>Order</Table.Head>
<Table.Head>Date</Table.Head>
<Table.Head>Customer</Table.Head>
<Table.Head>Payment</Table.Head>
<Table.Head>Fulfilment</Table.Head>
<Table.Head numeric>Total</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{ORDERS.map((order) => (
<Table.Row key={order.number} interactive>
<Table.Cell>
<Table.RowLink href={`#order-${order.number}`}>#{order.number}</Table.RowLink>
</Table.Cell>
<Table.Cell>
<time dateTime={order.placed}>{PLACED.format(new Date(order.placed))}</time>
</Table.Cell>
<Table.Cell>
<Inline gap="2">
<Avatar name={order.customer} size="sm" decorative />
{order.customer}
</Inline>
</Table.Cell>
<Table.Cell>
<Badge tone={PAYMENT[order.payment].tone}>{PAYMENT[order.payment].label}</Badge>
</Table.Cell>
<Table.Cell>
<Badge tone={FULFILLMENT[order.fulfillment].tone}>
{FULFILLMENT[order.fulfillment].label}
</Badge>
</Table.Cell>
<Table.Cell numeric>
<NumberValue value={order.total} format={USD} />
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
</Table.Container>
);
}
Notes
- One link per row. The order number is a
Table.RowLink, a stretched link: the whole row is its hit area and shows the hover, but the row is one Tab stop and the link's name is the order number. Never putrole="link"on a<tr>. - Two statuses, in words. Payment and fulfilment are separate Badges, as Figma draws them, and each says its state ("Paid", "Unfulfilled"); the tone only repeats the word.
- The customer. The Avatar is decorative because the name is printed next to it; without a photo it shows the initials, which Figma's raw ellipse could not.
- Dates.
Intl.DateTimeFormatwith an explicit locale and time zone, inside<time dateTime>, so the server and the browser print the same text and a locale picks its own 12 or 24 hour clock. Figma's "Oct 14, 09:12" is hard-coded English. - Money. Totals are
NumberValuein end-aligned tabular figures. A long currency needs no fixed column width: the table scrolls inside its named container rather than wrapping.
Product table
A catalogue table with row selection for bulk actions, a status Badge, the inventory and the price on each row, and a Menu of row actions named for its product.
Discount card
A discount code, what it gives, its status, how much of it is used as a Meter and its dates, including an expired state that keeps its contrast. A server composition; it ships no JavaScript.