About this concept

What it fixes

Today's list pages use one control for two jobs: the filter cards show big numbers and also act as tabs, while the real filters hide in an icon-only dialog. Rows open on double click only. Here each job has its own control.

Round 2: what changed and why

Built from three research boards in Figma: metric cards, list page layout, and summary stats. A check of 63 list pages showed that cards above a list are an established but minority pattern, and that no product splits cards and stats into two styles, so the stats column became one card in the row.

Principles

  1. Four bands, top to bottom: page header, slice cards, the table card (with its own header), and a floating bar while rows are selected. Each control lives in the band of the question it answers.
  2. The table card has a header, as in Shopify. "Add filter" and a bare search field on the left; the date range, a rule and the Display settings icon. Its menu is a short list of settings, each with its current value (Group by: None, Row height: Comfortable, Columns: All) opening a nested menu with a check by the choice. Sorting is in the column headers, and in this menu only on phones, where those are hidden on the right. Its filters still change the cards above. Scrolling follows option D from the "What stays on screen" research board: the page title scrolls away; once you are into the list, scrolling down hides the top bar and the card header (only the column header stays on desktop, only the tab bar on phones), and a few pixels back up brings them back in 300 ms. Menus, a focused field or Tab into either bar keep them in view.
  3. Search becomes a chip. Typing filters as you go; Enter (or leaving the field) turns the words into a chip, "Search: “basement”". Several chips must all match. Click a chip to edit its words, Backspace in the empty field takes back the last one, press / to jump to the field. The matched letters are marked in the rows, highlighter yellow, in the fields the search reads (the record's name and the line under it, and a customer's contact or an item's category and vendor), never in a column the search doesn't read, such as the owner. A second row shows the count ("23 of 132 jobs"), the chips and Clear all once something narrows the list; at rest the All card already gives the total.
  4. Add filter, then chips. Pick a field, then a value; it becomes a chip with ×. A field left without a value disappears again. A card is a filter too: picking one presses the card and adds its chip ("Status: Booked"), so the count row always says what narrowed the list; × on the chip, or the card again, takes it off.
  5. Built from the system (D33). This page is now the system's list page: warm in light (white cards with cement edges on a paper page, cement hovers and tints; text, inputs and the dark top bar keep Bolster's own neutral, selection stays blue) and cool in dark (Bolster's greys). Cards have a quiet body: a top line, a darker bottom edge, two shadows tinted with the page. What's left in the concept is its tooling and the grid on the page.
  6. A grid on the page, lit by the pointer (trying out, on by default). A faint grid, its cells half as tall as the page header and starting from the top-right corner so a line runs along the header's rule, sits on the page between the cards and brightens in a soft area around the pointer, trailing it a little; in dark, a soft blue-violet light sits under it. It's decoration only: behind the content, hidden from screen readers, never on the cards, and still on phones as a faint grid everywhere. Turn it off, or tune it, in Concept controls.
  7. Buttons below the primary (from the buttons research). Secondary is white with the primary’s body, quieter: a cement edge, a darker bottom edge, a small warm shadow, a 1 px lift. Tertiary is gone; the record’s actions are secondary. Ghost stays for toolbars, rows, bars and Close, with a hover you can see. Red means it can’t be undone: Delete is red text in menus and on the bulk bar (filling red when pointed at), and the filled red appears only on the confirmation, named for the outcome (“Delete 3 jobs” beside “Keep jobs”, which starts focused). Archive can be undone, so it isn’t red.
  8. Tactile cards (trying out, on by default). The buttons' body, quieter, so cards read as surfaces and buttons stay the things you press: a white line along the top, a darker bottom edge, a faint sheen and shade, and two shadows tinted with the page. The status cards are buttons, so they move: hover lifts them a pixel, a press sinks them, and the selected filter stays pressed in. Turn it off, pick a preset, or tune every value in Concept controls.
  9. Explanations use the screen’s own words (D27). Info notes name cards, statuses and columns exactly as the screen does, and show each status with its mark, as on its card. A term the screen doesn’t show (won, decided, invoiced) is defined once in the screen’s labels, then used the same way in the card’s own figures.
  10. Columns keep their width. Each column is measured, not guessed: as wide as the widest value it can ever hold across the whole list (every status, even one no row has yet, and its header); the first column takes the rest and is the only one that truncates. Sorting or loading more never moves a column, and every header keeps room for the sort arrow (it shows faintly on hover). A column never gets narrower than that: when they don't all fit, the table scrolls sideways in its card, with the checkbox and name pinned on the left, a rule at their edge once you've scrolled, and a fade on the right while there's more. The column header still follows the page, under the bars.
  11. Slice cards are the status filter. "All" plus one card per status; the whole card toggles and stays outlined. Amount first, count in the corner. Empty slices stay, dimmed. They count what the other filters let through, so a card's number is what you get when you click it.
  12. One card isn't a filter. The last card holds a rate worked out across the slices (win rate, collected) with its counts, a split bar in the status colours and an ⓘ with the formula, plus one more figure. Below 5 decided jobs the big figure is the count (“2 of 4”), not a rate; with none it reads “None decided yet” over an empty bar. Every state fills the same three lines, so filtering changes the numbers, never the card’s shape.
  13. The count is said once, by the filters ("55 of 132 jobs"). The footer shows the range and loads 25 more; rows also load as you scroll. No totals row in this view.
  14. Selection never moves the rows. A floating bar at the bottom: the count, Select all, three or four actions, the risky one last behind a confirmation that names the number, and ×. It's built to replace the other situational bars later.
  15. Rows open, "···" acts. One click opens a row; row actions sit in "···", shown on hover and focus. From 1280 wide the record opens beside the list, as in Mercury: the list keeps its name, status and amount columns, the opened row stays marked, and the record sticks under the bars. Below 1280 it is a sheet from the side, full width on phones. The record reads top to bottom: status, the amount, a timeline, two actions and More (one action and More when both don't fit on a line; the other moves into More), the details, then the document. The timeline runs oldest first: a solid line through what happened, then a dashed line to the next step, drawn as a hollow ring. On jobs each event wears the status shape it moved the job to: the circle fills a quarter at a time (created: dashed, sent: a quarter, approved: half, work started: three quarters; closed would be full), and declined is the slash. Long histories fold to "+ n more events". The sketch drops the view menu and refresh from the page header; saved views come back once we decide where they live.
  16. Before the name, a slot (D55). It holds what the list needs: the customer’s avatar on jobs, a photo on catalog items (Wikimedia Commons, open licences, credited in each item’s record), with a placeholder where there’s none or a link breaks.
  17. Status has a shape, not just a colour. Jobs: an empty circle for draft, a half-filled one for pending, a solid dot for booked, and a circle with a slash for declined (the client said no). One drawing on a 12px grid, 12px in the table badge and 14px on the cards. Draft and pending marks go a step darker than their old dots so each shape reaches 3:1.
  18. Every state is designed: loading, first-use empty, no results, and error. Switch between them in the concept controls.
  19. Live areas keep their shape (I13). What updates while you act elsewhere (filters, search, sort, selection) changes its values, never its layout. Every state fills the same slots at the same size, said by what a slot holds (“2 of 4”, “None decided yet”, an empty bar), not by lines coming and going. Sizes come from the whole list, not the rows on screen; optional parts leave a placeholder; anything that comes and goes appears where you acted or floats; a redraw never moves the page or your focus.
  20. Phones: the insight card (Win rate) leads the card row so the overview is in the first screen; cards and chips scroll sideways, the floating bar gives its actions their own row above the tab bar, and every menu and filter opens as a bottom sheet; a nested menu opens inside the sheet with a back row.
  21. Built from a description (D31). Turn on “Lists built from page descriptions” in Concept controls and the four lists are drawn from their page descriptions (system/recipes/list/concept) by recipe.js, with sample rows made from each column’s type, instead of the hand-written data.js. A note on each list says what the renderer can’t draw yet (custom figures like Win rate). Any description opens with ?d=path.
  22. Phones: rows have four corners (D32). The number and a date on a quiet overline, the amount top right, the name across the full width at 16 px (it wraps to two lines rather than being cut), then the address, job or unit and the status. There's no checkbox column: Select in the page header, or a long press on a row, starts selecting; the boxes slide in and a tap ticks instead of opening.
  23. Phones: Create floats (D29). “+ Create job” leaves the page header and floats bottom right above the tab bar, shrinks to + while you scroll down, and makes way for the bulk bar while rows are ticked.

Open questions

  • Does every list need cards? Tabs with counts would do the filtering in less height; the catalog already has neither.
  • The insight card scrolls out of view below about 1,300px wide. Move it first, or drop it on narrow screens?
  • Should cards be single-choice (as now) or add to a multi-select status filter? Today a multi-select status shows as a chip and no card is selected.
  • Auto-loading on scroll, or only on "Load more"? Export and "Select all" already work on every matching row, not just the loaded ones.
  • Which other floating bars should this one replace first?
  • Create job scrolls away with the page title. Keep a compact Create in the card header once you are into the list, or accept a scroll up?
  • Where the concept still breaks I13: the chips row pushes the table down when the first filter is added; filtering to nothing collapses the table under the pointer.
  • Shapes for the other lists: invoices (draft empty, outstanding half, paid full, overdue?) and customers. Should the shape mean progress everywhere, with a separate one for "stopped"?
Concept Controls

"No results" shows up when filters exclude everything.

The same four lists, drawn from system/recipes/list/concept/*.json by recipe.js instead of the hand-written data.js.

The design system (back office) Components, and who decided them