The UX nobody sees: designing an e-commerce back-office that people can actually work in
Consumer UX advice optimises for first impressions. E-commerce operations optimise for product readiness, speed and consistency: suppliers, NGPs, categories, gender, stock, campaigns and the long pipeline before a product goes live.
Somewhere, a customer is about to see a perfectly ordinary product card: a shoe, a title, a price and a reassuringly clickable button.
What they do not see is the small bureaucratic opera that happened before that moment. A supplier sent a feed. An NGP was created. Someone mapped a category. Someone else fixed the gender. Images were checked. Stock was reconciled. Attributes were enriched. Rules argued with each other. A campaign decided whether the product was invited. Only then did the product earn the right to exist on the website.
This is why I find generic advice about design systems slightly suspicious. Most of it assumes you are designing for someone browsing for a few minutes. In operational e-commerce, the user might spend eight hours moving through suppliers, products, categories, campaigns and validation queues. They are not exploring. They are trying to get 847 things ready before someone asks why the campaign is still blocked.
Back-office is a different design problem#
Consumer interfaces and operational interfaces disagree on nearly every default. Import the instincts of one into the other and you get a lovely interface that quietly makes experienced users slower.
| Consumer product instinct | Operational e-commerce reality |
|---|---|
| Brand expression is everywhere | Brand gets out of the way; status and data carry meaning |
| Generous whitespace | High information density |
| One primary action | Many actions, often in bulk |
| A table is a component | A table is an operational subsystem |
| A product is content | A product is a state machine |
| Visitors stay for minutes | Operators work for hours |
| Redesign every few years | The system needs to survive organisational archaeology |
Density is a decision, not a smaller padding token#
Here is a recurring UX conversation: someone looks at an operational table and says, "It feels crowded." The operator looks back, because they have 800 SKUs to validate before lunch, and wonders if the whitespace is going to help.
Density is not about cramming more things into a rectangle. It is about reducing unnecessary interaction while preserving hierarchy.
- A tight spacing scale with a 4px base.
- A smaller base font when the domain supports it.
- Rows around 32–40px for repetitive operational work.
- A real comfortable/compact density mode driven by tokens.
- Keyboard navigation that makes dense interfaces faster, not harder.
A product is not ready because someone says it is#
In an e-commerce back-office, "ready" is usually a computed conclusion. Category complete. Gender mapped. Required attributes present. Images valid. Stock available. Price valid. Campaign eligible.
This changes the UX problem. A good interface does not merely show a status. It helps the operator understand why something is blocked and what needs to happen next. A red badge saying INCOMPLETE is not useful if the user still has to visit six screens to find the missing image.
The table is a subsystem, so treat it like one#
Most operational e-commerce screens are a list and something you need to do to that list. Products by supplier. SKUs by campaign. Stock by warehouse. NGPs by state. If the system ships a thin wrapper around<table>, every team eventually rebuilds the rest.
- Column types: text, number, currency, date, status and custom.
- Filtering across supplier, category, gender, campaign and state.
- Sort, hide, reorder, resize and pin columns.
- Selection across pages and honest bulk-action counts.
- Bulk validation and partial failure states.
- Loading, empty, no-results and error states as distinct concepts.
- Saved views because operators should not rebuild the same filters every morning.
Build the behaviour once on a headless core and own the defaults. The API should describe data and intent rather than force every screen author to invent interaction patterns again.
<DataTable
data={products}
columns={[
{ id: 'ngp', header: 'NGP', accessor: 'ngp', pin: 'left' },
{ id: 'supplier', header: 'Supplier', accessor: 'supplier.name' },
{ id: 'category', header: 'Category', accessor: 'category.path' },
{ id: 'gender', header: 'Gender', accessor: 'gender' },
{ id: 'stock', header: 'Stock', accessor: 'stock', type: 'number', align: 'end' },
{ id: 'status', header: 'Readiness', accessor: 'status', type: 'status' },
]}
bulkActions={[
{ label: 'Assign category', onSelect: assignCategory },
{ label: 'Validate selected', onSelect: validateProducts },
]}
savedViewsKey="catalogue.products"
/>Forms are the second subsystem#
The same applies to forms. An operator creating or enriching products does not need a magical onboarding experience every time. They need labels, predictable tab order, visible validation and a fast route through fields they already understand.
- Dense multi-column layouts with deliberate keyboard order.
- Labels always visible; placeholders are not documentation.
- Validation on blur rather than punishment on every keystroke.
- Server errors mapped back to the fields that caused them.
- Unsaved-change protection for long enrichment workflows.
- Actions such as “Save and validate next” for repetitive work.
The customer sees the tip of the iceberg#
One reason back-office UX is difficult is that success is often invisible. When everything works, the customer simply sees a product and assumes it has always existed.
Colour carries meaning, so use a semantic system#
In operational products, colour is information: validation, severity, publication state, stock warnings and environments. A brand palette does not solve this by itself.
- A long neutral ramp for dense information hierarchy.
- Semantic intents: success, warning, danger, info and neutral.
- Background, border, text and solid variants for each intent.
- Non-colour signals: labels, icons or position.
:root {
--intent-danger-text: #b42318;
--intent-danger-bg: #fef3f2;
--intent-danger-border: #fda29b;
--row-h: 36px;
--control-h: 32px;
}
[data-density="comfortable"] {
--row-h: 48px;
--control-h: 40px;
}Atoms, molecules, and what the system actually ships#
The answer is not a component for every rectangle. It is a small set of atoms, a set of composable molecules, and a few serious organisms. The table is one of those organisms. Product readiness might be another.
Build on headless, skin it thin#
The useful distinction is not build versus buy. It is deciding which layer is worth owning. Tokens and visual language are yours. Keyboard behaviour, focus management and grid engines are specialised problems where headless primitives can save years of reinvention.
| Layer | Own it? | Why |
|---|---|---|
| Design tokens | Yes | They outlive framework decisions |
| App shell and layout | Yes | They encode your operational model |
| Behaviour and accessibility | Usually headless | Hard, specialised and reusable |
| Grid engine | Wrap it | Sorting and virtualisation are not your differentiator |
| Presentational components | Yes | This is the design system |
| Icons | Adopt | Nobody needs to draw 400 icons |
Tailwind + headless, or a themed component library?
The honest answer is timeline-dependent. A themed component library can get an operational tool useful quickly. A thin layer over headless primitives gives a larger organisation more control over long-term consistency. The important rule is the same: applications consume your wrapper layer, not raw dependencies.
A back-office design system is mostly two subsystems done properly: the table and the form. Everything else is the discipline required to stop twenty teams from inventing a twenty-first version of both.
The system is governance, not a component folder#
A design system succeeds when a user moving from catalogue enrichment to campaign management feels like they are still inside the same product. That is an organisational outcome.
- Versioning. Semver the package and write a deprecation policy.
- Contribution. Useful domain components return to the shared system rather than becoming permanent local forks.
- Metrics. Track current-major adoption, raw-value usage and local overrides.
- Domain language. Agree on what supplier, merchant, NGP, campaign and readiness mean before components encode five different interpretations.
Accessibility is not the compliance section#
Accessibility and speed often point in the same direction in operational tools. Full keyboard operation helps power users. Visible focus helps everyone. Clear error summaries prevent expensive mistakes.
- Keyboard operation for tables, forms and dialogs.
- Visible focus states that survive compact density.
- Error summaries with managed focus.
- Reduced motion support.
- Targets that remain usable in compact mode.
Failure modes#
- The back-office designed like a marketing landing page.
- A beautiful Figma library with no implementation contract.
- Every team creating its own table because the shared one is too generic.
- Generic statuses that hide the actual reason a product cannot go live.
- A system team becoming a bottleneck, so teams route around it.
- Domain terminology drifting until supplier, merchant and owner mean different things in different tools.
The checklist#
- Model the operational pipeline, not just individual screens.
- Make density a token-level decision.
- Treat product readiness as explainable state, not decoration.
- Build one serious
<DataTable>rather than ten approximate ones. - Use forms optimised for repetition and expertise.
- Use semantic colour and never colour alone.
- Own tokens and the visual skin; borrow complex behaviour where appropriate.
- Keep applications away from raw component-library APIs.
- Run contributions, versioning and migration as governance.
- Measure whether the system is actually being used.