Invisible Details

Course

Foundation

  1. Introduction
  2. Learning to notice
  3. Small details that add up
  4. Predictability is a feature

Designing Interface Behavior

  1. Designing States
  2. Feedback is a conversation
  3. Forgiving Input
  4. Interfaces should remember

Interaction Feel & Usability

  1. Speed is a feeling
  2. The weight of a click
  3. Designing for Keyboard

Language & Complexity

  1. Words shape expectations
  2. WYSIWYG editor is hard

Practice

Foundation

  1. Introduction

Basic UI Patterns

  1. Stepper
  2. Tree
  3. Action modal

Data Visualization

  1. GitHub activity chart
  2. Charts

Input & Selection

  1. Date picker

Unlimited access. One purchase.

LoginGet access
Basic UI Patterns / Stepper
  1. Stepper
  2. Telling you which way you're going
  3. Moving without a mouse
  4. Bigger than they look
  5. Saying it out loud
  6. Turning motion off
  7. The fast-clicker case

#Stepper

The stepper comes into play when there is just too much to handle all at once. It may appear when you start the process of onboarding, during a guided tour through settings, while checking out or working through a form split across several pages.

Account
Click the stepper

A long form is scary. Ten fields on one screen feel like too much. Split them into four small steps and each one feels easy. It is the same form -  — you just see less of it at a time. That is the whole point of a stepper.

It makes a big task feel small.

The same trick works in the code. Just like the form is split into steps, the component is split into small parts -  — that is what a compound component is. The hard logic -  — focus, the active step, the animations -  — stays hidden, so you never touch it. You just put together a few simple pieces: a root, the step indicators and the content cards.

#Telling you which way you're going

The first thing I want to talk through is direction. When the user moves forward, the panel slides up from the bottom. When they move back, it comes down from the top. Also, the title moves the same way. Although this little detail won't make anyone say "nice animation", it gives the user an answer on what they are actually doing: am I moving deeper into this folder or going out of it?

Of course, without these nuances the animation still works smoothly. It just stops telling the user which way they are going.

You might ask why the panels move up and down instead of left and right. There is no single answer -  — it comes down to your layout. If the stepper sits on the left of the page with a product illustration on the right, your eye is already moving left to right across that layout, so the content should slide sideways too -  — up and down would feel off. But if the page is just the stepper on its own, there is no strong pull either way: up-down or left-right both feel fine.

1
2
3
One
Forward - Slides up
1
2
3
One
Back - Slides down
1
2
3
One
Forward - Slides up
1
2
3
One
Back - Slides down

#Moving without a mouse

Since a stepper consists of controls, there should be just one TabTab stop instead of many. You simply TabTab to the current step and then the arrows take over.

The leftleft and rightright arrows do the obvious thingmove to the previous or next step. I handle and too: goes to the next step like and to the previous one like . That way a vertical arrow still does something instead of nothing. Then and jump straight to the first and last step, the way they do everywhere else.

-  — 
upup
downdown
upup
rightright
downdown
leftleft
HomeHome
EndEnd

Steps that are disabled at the time are bypassed when navigating the stepper. That way, the user doesn't get stuck on a disabled step.

OneTwoThreeFour

Tap a step, or focus the row and use the arrows, Home and End. Three is disabled, so it gets skipped.

#Bigger than they look

The buttons that switch steps are 20×20px, which means that even using a mouse may be a challenge and clicking these elements on a smartphone is practically impossible. It is easy to miss the step you meant to press.

To fix that we can increase the clickable area without changing how it looks. A pseudo-element with a negative inset styles can increase the clickable region past the visible square -  — the step still looks like a small 20px dot, but it catches presses from a wider zone around it.

The one rule is on the x axis: the zones must not overlap. If two neighbouring steps share hit area, a press near the edge is ambiguous and the wrong step fires -  — that confuses the user more than a small target ever would. So the horizontal growth stops right at the gap between steps. Vertically there is nothing to bump into, so it can grow more.

The result is that 20×20px becomes 26×36px and all that area is clickable. Besides, gaps between the steps, which were dead zone before, are now assigned to the react to the nearest step button.

26px
36px
Show guides

#Saying it out loud

A screen reader doesn't see the slide or the highlight, so all of that has to be said out loud instead -  — and this is where most stepper implementations break down.

Each step has an aria-label so it describes itself in terms other than "button". The current step is marked with aria-current="step". That is the key part: it tells the user which step they are on, not just that steps exist. The disabled steps declare themselves as such rather than remaining gray and silent.

That is also why I don't hang a tooltip on each step. A tooltip displays when you hover over an element, but that means it is only useful for a mouse user. Both the keyboard user and the screen reader user get no value from it.

"Account, current step"

"Shipping"

"Payment"

"Review, dimmed"

"Account, current step"

"Shipping"

"Payment"

"Review, dimmed"

With aria

"button"

"button"

"button"

"button"

Without aria

#Turning motion off

Some people turn on reduce motion in their system settings. We respect that -  — a setting the user chose should always win over ours. So when prefers-reduced-motion is on, I turn off everything: the slides, the label, the color changes, even the hover.

You can't always drop every animation -  — sometimes the motion actually means something. But the stepper is simple, nothing here depends on the movement, so all of it can go. It still works the same, it just snaps instead of gliding.

1
2
3
One
Motion
1
2
3
One
Reduced motion
1
2
3
One
Motion
1
2
3
One
Reduced motion

#The fast-clicker case

This is another small detail that starts out as an annoyance and turns into a tiny feature. When the steps switch faster than about 120ms apart, I drop the animation for that change, because otherwise the slides pile up on each other and the whole thing stutters.

It is rare, but it happens. If the button never moves and some steps are optional, the user can just click through them fast -  — one change right after another. That is the case this handles: while they click fast, the animation drops out, so nothing stutters.

1
2
3
4
One

The steps change faster than the threshold, so every move snaps with no animation

None of this shows up in a screenshot. It shows up on the third click, when the value lands exactly where the user expected it to land. How much someone trusts the form underneath always depends on how the steps behave.