Skip to content
Brand guide

Chapter 09

UX principles

Seven rules that decide arguments. Where a design question has two defensible answers, these are how Since Labs picks.

9.1 Answer one question per surface

A page that answers two questions answers neither. The product's own IA is built on this: Home answers what happened, Apps answers where do I go. Merging them works at three apps and falls apart at fifty.

Before building a page, write the question it answers in one sentence. If you need "and", you need two pages.


9.2 Fixed chrome, growing content

The platform sidebar is four items, forever: Home, Apps, Team, Organization. Apps are reached through the ⌘K launcher and the catalogue — they never join the nav.

This is the single most important structural decision in the product. Any navigation that grows with the number of things it lists has a ceiling, and you hit it in production, in front of a customer, with no cheap fix. Chrome is fixed. Content grows.

The same rule governs the operator console: per-app back-office surfaces hang off /admin/apps from each app's manifest, so the operator nav does not grow either.


9.3 Search beats browse past about fifteen

A dropdown of everything works up to roughly fifteen items and then quietly stops. Typing is O(1) in the number of items.

So: the app switcher is search-first, on ⌘K, from anywhere. Anything expected to exceed fifteen entries gets a search field before it gets a filter menu.


9.4 Progressive disclosure, one branch at a time

Sub-navigation reveals only while its parent branch is current. The sidebar never shows two app sections expanded at once.

Generally: show the next decision, not every possible decision. Detail lives one click in, not in an accordion stack on the index.


9.5 Destructive actions are confirmed, reversible, and logged

Three requirements, all of them:

  1. Confirmed in a real <dialog> with showModal() — never a <details> popover. A popover inside a card with overflow-hidden gets clipped, and the confirm button becomes unreachable on the last row of a table. This has actually happened here.
  2. Named. The confirmation says what is about to happen, to what: "Delete Maanrakennus Virtanen Oy and all of its data?" — not "Are you sure?"
  3. Logged. Anything destructive writes to the audit log with an actor and a reason.

The confirm button carries the destructive variant and repeats the verb: Delete organization, not Confirm.


9.6 State is never a mystery

Every surface has a designed state for all five:

StateRequirement
LoadingA skeleton over a spinner. Nothing at all under ~300ms
EmptySays what is not here and what to do. Never a shrug
PartialSays what is missing — "Environmental only", "Partial data" — not a blank cell
ErrorSays what happened and what to do. Degrades the region, never the page
SuccessVisible confirmation. A silent save is a bug report

A page that reads "0" and a page that failed to load must never look the same.


9.7 Nothing is communicated by colour alone

A status chip carries a dot and a word. A chart series is labelled directly. A required field is marked in text, not by a red border.

This is WCAG 1.4.1, and it is also just correct for an audience reading a phone in daylight on a job site.


9.8 Keyboard is a first-class input

  • ⌘K / Ctrl-K opens the switcher from anywhere.
  • move, opens, Esc closes — in every list, dialog and palette.
  • Tab order follows visual order. Focus moves into a dialog on open and returns to the trigger on close.
  • The focus ring is never removed without an equivalent replacement.
  • Every interactive element is reachable without a mouse. If it is a <div> with an onClick, it is a bug.

9.9 Operator and customer are different products

The same codebase serves two audiences with different needs, and they get different vocabularies:

Workspace (customer)Operator console (staff)
DensityComfortableDense
IdentifiersHiddenVisible, in mono
LanguagePlain — "Your apps"Precise — "Entitlements"
ErrorsWhat to do nextWhat happened, with the ID
Role shownMembership roleInternal rank

Never leak operator vocabulary into the workspace. A customer should never see the word "entitlement", a UUID, or an internal role name.


9.10 The five-second test

Export any screen or asset. Look at it for five seconds. Close it. Write down what you remember.

If you cannot recall the main message, the hierarchy is wrong — start again. This applies to a dashboard as much as to a LinkedIn cover.

This chapter as plain markdown: /docs/ux-principles.md