Orders Table
The merchant’s orders index with saved views, filters and bulk actions. Handles partial payment and fulfillment, live orders and partial bulk failures.
Orders Table is the orders index of a store admin. Each order shows its number, a relative date with the exact time on hover, the customer, channel, total, payment and fulfillment status, item count, delivery method and tags. Payment and fulfillment are separate pills, and each has a progress glyph (an empty, half or full circle) so Partially paid or Partially fulfilled reads without relying on color.
Saved views sit in tabs: All, Unfulfilled, Unpaid, Open, Archived and your own. A view is a set of filters, a sort and a search. Change any of them and the tab is marked Modified, with Reset, Update view and Save as new view. Filter chips cover status, payment, fulfillment, date, channel, tag and risk. ordersQueryToSearchParams and ordersQueryFromSearchParams keep the whole query in the URL, so a link opens the same list and Back works.
Selection works like a desktop list. Shift-click selects a range, the header checkbox selects the page, then Select all 48 orders selects every match. The bulk bar takes the header’s place, so nothing shifts. Mark as fulfilled, Capture payment (with a confirmation showing the amount), Add tags, Archive and Print packing slips are async. Partial failures name the orders that failed with a View link, and Archive can be undone. J and K move a focus ring, X selects, Enter opens, / searches and Esc clears.
New orders that arrive while you browse slide in at the top with a soft highlight. While a row is focused or anything is selected, rows never move: a “1 new order · Show” pill waits instead. The table tells an empty store (No orders yet, Create order) from a filtered empty list (No orders match these filters, Clear filters), shows skeleton rows while loading and an error with Retry. On phones the rows become cards and the bulk bar floats at the bottom.
From the Shopify Admin API
toShopifySearch turns the view, filters and search into an orders(query:) string, and toShopifyVariables adds the sort key and page size. Archived maps to status:closed, and partial states map to Shopify’s financial and fulfillment filters.
Server-side pagination with cursors
Keep the query in the URL with the search param helpers, pass serverSide and totalCount, and remember each page’s endCursor so Next and Previous reuse them. Loading, errors and Retry stay inside the table.
Bulk actions with partial failures
onBulkAction gets the action and the selection, either explicit ids or allMatching with the query. Return the ids that failed with a short reason and the table reports “Fulfilled 5 orders. 1 couldn’t be fulfilled: #1031 is on hold” with a View link.
構造
外側から内側へ組み合わせるパーツ。
| パーツ | 説明 |
|---|---|
OrdersTable | Views, toolbar, the table or phone cards, the bulk bar and pagination. |
PaymentStatusPill, FulfillmentStatusPill | Outline pills with a progress glyph and a hidden “Payment:” or “Fulfillment:” prefix. |
applyOrdersQuery, filterOrders, sortOrders | Filter, search, sort and paginate orders on the client or the server. |
ordersQueryToSearchParams, ordersQueryFromSearchParams | Read and write the view, filters, sort, search and page as URL params. |
defaultViews, queryForView, isViewModified | The built-in views and helpers to apply one or tell whether the query has drifted from it. |
OrdersTable
Also takes div props.
| プロパティ | 型 | デフォルト |
|---|---|---|
ordersEvery order in client mode, or the current page with serverSide. OrdersTableOrder is Order plus optional closedAt (archived) and test. | OrdersTableOrder[] | – |
queryThe view, filters, sort, search and page, when controlled. | OrdersQuery | – |
defaultQueryThe starting query when uncontrolled. | Partial<OrdersQuery> | – |
onQueryChangeCalled on every change. Write it to the URL with ordersQueryToSearchParams. | (query: OrdersQuery) => void | – |
viewsSaved views in tab order. Pair with onViewsChange to persist custom views. | OrdersView[] | defaultViews |
onViewsChangeCalled when a view is saved, updated or deleted. | (views: OrdersView[]) => void | – |
visibleColumnsShown columns, controlled. defaultVisibleColumns and onVisibleColumnsChange work the same way. | OrdersColumn[] | – |
serverSideTreat orders as an already filtered page. Pass totalCount and, optionally, viewCounts. | boolean | false |
totalCountOrders that match the query, for “1–20 of 48” and Select all. | number | – |
pageSizeRows per page. | number | 20 |
loadingShow skeleton rows. | boolean | – |
errorShow the error state with this message. | ReactNode | – |
onRetryShows Retry in the error state. A promise keeps the button busy. | () => unknown | – |
onOpenOrderCalled on row click and Enter. | (order) => void | – |
onCreateOrderShows Create order in the empty store state. | () => void | – |
onBulkActionRun a bulk action. Return { failed: [{ id, message }] } for partial failures, or throw to show the whole action failed. | (action, selection) => OrdersBulkResult | Promise<OrdersBulkResult> | – |
nowThe time relative dates and date filters use. Pass it for stable server rendering. | Date | string | number | – |
timeZoneThe shop time zone for Today and Yesterday. | string | – |
localeLocale for dates and money. | Intl.LocalesArgument | "en-US" |
labelsEvery visible string, including result messages. | Partial<OrdersTableLabels> | – |
| プロパティ | 型 | デフォルト |
|---|---|---|
viewThe selected view id. | string | – |
filtersLists match any value. date is today, 7d, 30d or 90d. | { status?, payment?, fulfillment?, date?, channel?, tag?, risk? } | – |
sortThe sort. | { key: "date" | "order" | "customer" | "total" | "items"; direction } | – |
searchMatches order number, customer, email, SKU, product and tag. | string | – |
page1-based page. | number | – |
| プロパティ | 型 | デフォルト |
|---|---|---|
idsSelected order ids. With allMatching in client mode, every matching id. | string[] | – |
allMatchingEvery order that matches query is selected, including ones not loaded. | boolean | – |
queryThe query the selection was made under. | OrdersQuery | – |
countHow many orders the action covers. | number | – |
| キー | アクション |
|---|---|
| JArrowDown | Moves focus to the next order. |
| KArrowUp | Moves focus to the previous order. |
| XSpace | Selects or clears the focused order. |
| ShiftJ | Extends the selection to the next order. Shift+K goes up. |
| Enter | Opens the focused order. |
| / | Focuses search. |
| Escape | Clears the selection. |
| ? | Shows the shortcuts. |
- Rows use a roving tab stop, so the list is one Tab stop and J, K or the arrows move inside it. The focused row gets a background and an edge bar, and forced colors mode gets an outline.
- Status is never color alone: each pill has an empty, half or full glyph and its words, with a hidden Payment or Fulfillment prefix. High risk orders have a warning icon with a text label.
- A polite live region announces selection counts, new orders and bulk results, such as “Fulfilled 5 orders. 1 couldn’t be fulfilled: #1031 is on hold.” Errors use role alert.
- The bulk bar is a labelled toolbar. Disabled actions stay focusable and explain why in a tooltip. When an action finishes, focus returns to the select-all checkbox instead of being lost.
使用技術
Orders Table を構成する無料のHextaUIコンポーネントです。それぞれ単独でインストールできます。
コード
8 個のファイルを components/blocks/orders-table に追加しました。