It's on This Page. Somewhere.

How semantic primitives cut decision time from 18s to 4s across 14 entity types.

Client

Locus

acquired by IKEA (INGKA Group)

Product

Detail Page Framework

Year

2026

Timeline

3 weeks

Role

Senior Product Designer

Owned the V2 framework end to end

Team

1 Product Manager 4 Engineers (FE+BE)

At a glance

Problem

Schema-driven detail pages rendered every entity identically. Operations teams couldn't recognize what they were looking at or find what they needed under time pressure.

Solution

Introduced two semantic primitives into the schema contract: slots (grouping) and detail types (meaning). Together they let schemas communicate what data represents, not just list what fields exist.

Result

14 entity detail pages shipped with no custom UI. Task completion 4.5× faster in controlled testing. Piloted with 5 clients before scaling to 13 more.

Context

Locus is a logistics platform for enterprise route optimization. We were re-architecting the platform around schema-driven UI: every detail page renders from a backend JSON schema, and one generic frontend renderer handles all entities. Before the replatform, each entity had handcrafted detail pages. Schema-driven UI stripped that out in exchange for scalability.

Each entity is a JSON schema. One renderer turns them all into detail pages.

Detail pages are the highest-traffic screens in the platform. Order details alone: 2.57M views over 180 days. Operations coordinators check them 40-50 times a day. Every second spent searching compounds across hundreds of time-sensitive decisions.

Locus had 14 entities in the platform with 20+ planned. Orders, shipments, tours, drivers, vehicles, warehouses, teams, locations. Each one a different data model. The schema was doing its job. Nothing in the metrics flagged a problem.

The problem

Users were pressing Ctrl+F on pages they had seen hundreds of times. Not because the data was missing. Because the only way to find anything was to scan a flat wall of label-value pairs from top to bottom.

Ctrl+F on a page you've seen hundreds of times.
That's a design failure, not a user one.

These were Technical Account Managers. People who knew Locus inside out. Their feedback was consistent:

"All the detail pages look the same."
"I can't tell what I'm looking at."
"It is very difficult to find what I am looking for."

Two different entities. One identical page.

The second quote is the one that mattered. Not "I can't find it" but "I can't tell what I'm looking at." That's a recognition problem, not a navigation one.

The problem was semantic, not visual

Simple question: "Is this shipment late?"

The answer existed on the page. To get it, users had to find the planned pickup time, find the actual pickup time, and calculate the difference themselves. Two fields. No logic. No answer.

Every section rendered identically.
Routes, contacts, timestamps, all flattened into the same label-value grid.

Because the schema only knew how to list fields, it rendered every entity the same way. A shipment and a driver profile produced the same visual structure. Same heading levels. Same four-column grid. Same everything.

The schema was a data contract. It described what fields exist. It had no way to describe what those fields mean.

Without that, every entity looked identical because to the system, every entity was identical. The platform was scaling. The framework wasn't.

Why visual fixes failed

My first instinct was that this was a visual problem. The pages looked flat. Maybe better structure would fix it.

I ran four explorations: nested containers, hierarchy lines, indentation with dividers, indentation alone. Each one was a genuine attempt to add visual order to the flat grid.

Nested containers, hierarchy lines, indentation with dividers, indentation only.

I brought all four to the design team. Laid them out. Asked which direction to move forward with.

The lead designer looked at them and said: "Why are we working on beautification?"

That stopped the room.

She wasn't wrong. Every exploration was cosmetic. Rearranging the surface without touching the structure underneath. The pages still had the same problem they started with. They just had more visual decoration on top of it.

Finding the real problem

I went back to the drawing board. Not to design a solution. To understand what was actually broken.

I picked the most complex entity in the platform: shipment details. And I did the opposite of what schema-driven development demanded. I handcrafted it. No schema constraints. No renderer rules. Just me and the data.

Built by hand to find what the framework couldn't express.

Two problems surfaced immediately.

No way to group information without adding a new heading. The only grouping mechanism was a new section heading. Nothing below that level. A shipper's name, phone, and address sat in the same flat grid as a route's origin, stops, and destination.

No way to represent data meaningfully. A route wasn't visualised as a journey. A contact wasn't presented as a person. Every field looked identical to every other field. Users had to hold the entire page in memory because nothing communicated what it was at a glance.

The framework had no vocabulary for grouping and no vocabulary for meaning. No visual fix could supply what the schema contract didn't have.

The problem was not how things looked. It was what the system could say.

I was working under three constraints: schema-first UI, no custom pages, no entity-specific exceptions. If the framework couldn't express it, I had to evolve the framework. Not work around it.

Getting Backend aligned

Backend engineers were concerned about timeline. Implementing semantic properties across all entities at once felt like too large a risk with deadlines nearby. I proposed starting with the 3 highest-traffic entities and expanding from there. That removed the blocker. We moved forward incrementally, confirming each addition was backward-compatible before proposing the next.

Two semantic primitives

Slots

A slot is a container within a heading level. It allows related fields to be grouped intentionally, independent of the column layout.

For e.g. origin node and pickup time in one slot. Destination node and delivery time in another. Each group stays together. Each group can be sized to fit its content.

Detail types

A detail type defines what a group of fields represents. It gives the system the vocabulary to present data according to its meaning, not just its structure.

  • Movement renders a journey as a visual path: origin, stops, destination, with on-time status inline.

  • Location + Map renders coordinates alongside a spatial map.

  • Contact renders a person or company as a card: name, phone, address together.

Why two primitives, not one

Slots define grouping. Detail types define meaning. The separation was deliberate. A single primitive that handles both forces you to encode layout decisions as semantic rules. The moment a new entity doesn't fit the assumed shape, the whole system breaks. Keeping them separate means any detail type works in any slot configuration without either primitive needing to change.

Together, they let the schema say: "This is a journey. Show it like one." Before, it could only say: "Here are four fields."

Detail types on the left. Slot-based layout on the right. Any detail type plugs into any slot.

The atomic level

Enriched label-value pairs

The same principle applied one level down. I redesigned the label-value pair itself to carry meaning. A status tag next to a date field answers "on time or late" without requiring mental calculation. An icon distinguishes a phone number from an address at a glance. Supporting text adds context without adding fields.

Label and value are required. Everything else is semantic enrichment.

For e.g. a status tag next to a date field answers "on time or late" without requiring mental calculation. Supporting text adds context without adding fields.

Before: two fields, no logic. After: one answer.

Scaling to 14 entities

I designed detail pages for all 14 entities myself and handed them to engineering. We implemented the order detail page first, going through several rounds until the output matched intent. After that, the team had enough context to implement the rest with lighter involvement from me.

Most entities became visually distinct through semantic expression alone, no custom UI. A few, like the Team entity, had no data that warranted meaningful grouping. For those, the framework falls back to default label-value presentation. The goal was not to force richness everywhere. It was to enable meaning where it exists.

Validation

We ran task-based testing with 6 TAMs on the old framework and V2 using three tasks: determine whether a shipment is late, locate the pickup agent's contact, trace the route from origin to destination.

Small sample caveat: 6 internal power users under controlled conditions. Not production measurement. Take the numbers as directional signals, not proof.

4.5x faster

Time to answer "Is this shipment late?" dropped from 18s to 4s

0 Ctrl+F

Zero participants searched on V2. Two of six did on V1

1st fold

Route visible without scrolling. Previously required 3 scrolls

Same data. Different comprehension speed.

Protecting the system

Semantic systems are harder to govern than visual ones. I put a gate in place: new detail types require joint design-engineering review, must demonstrate reuse across at least two entities, and cannot duplicate existing capabilities. Three of the first four requests were rejected.

What I'd do differently

Instrument production. Task-based testing told us the framework worked under controlled conditions. Heatmaps and time-on-task data in production would have told us how it performed under real cognitive load, across all user types, at scale.

Test with dispatchers, not just TAMs. TAMs are power users. The people making 40-50 decisions a day under real time pressure might have surfaced problems the controlled tests didn't.

What this changed

Engineering adopted the framework as the default pattern for any new entity. PMs stopped requesting custom pages and started defining entity semantics instead. New entities no longer start with a design conversation. They start with a schema question: what does this data mean, and how should the system express it.

Before, the schema rendered data. After, the schema communicates meaning. That distinction is what scales.

Detail pages stopped being a design problem. They became a reusable platform capability.

The unexpected lesson: the same change that helped experienced users find information faster helped new users learn the system faster. We optimized for recognition. We accidentally unlocked learnability.

Create a free website with Framer, the website builder loved by startups, designers and agencies.