Build · Craft
Sanding the interface

Sanding the interface

Jim Nielsen describes how he develops in Sanding UI (September 2024): build something, click around a ton, tweak, click around more, until done. The clicking is the important part.

Sand until no splinters#

For a page transition that means going back and forth every way a person might: back button, context menu Back, in-app navigation, keyboard shortcut. He prefers the woodworking picture to QA: belt sander, then hand sander, then run your hand over it and feel for splinters, “until I finally cannot give myself any more splinters.” That is .

His example: a radio and its label in a flexbox with gap, and the gap was a dead spot where clicking did not toggle the control. Removing the gap and padding the label made the whole thing clickable. “Lots of small splinters lead to an agonizing experience.” In Sanding UI, pt. II (February 2025) a thumbs up/down widget, clicked a lot, selects its SVG as if it were text; one fix is user-select: none.

CSSJim Nielsen, Sanding UI
.container {  display: flex;  flex-direction: row;  align-items: center;  gap: .5rem;}

Focus rings at the declaration level#

Rauno Freiberg’s Crafting the Next.js Website sands at the level of CSS declarations. Tab through any site and you find rings in different colours and shapes. His model is the Discord web app: always a custom blue, matching the trigger’s radius, offset with padding, a radius even on links, never clipped by a container. One page is easy; the difficulty is a surface area shared by many teams.

His own is two box-shadows on :focus-visible: the first pads the element in the page background colour, the second draws a 2px outline. It assumes the element sits on the app background, barely noticeable when false. outline would do, but Safari did not follow the radius until 16.4, and Safari updates are tied to macOS. For links, a 2px radius, 2px of padding, and a negative margin that cancels it improve the focus state even though the radius is invisible until focused.

CSSRauno Freiberg, Crafting the Next.js Website
&:focus-visible {  transition: none;  box-shadow: 0 0 0 2px var(--app-background), 0 0 0 4px var(--focus-color);}.link {  border-radius: 2px;  padding-left: 2px;  margin-left: -2px;}

The figure below makes those two rules interactive. Switch between the box-shadow and outline techniques and tab through the samples to compare them.

Applied on :focus-visible
box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--signal);
Docs
Focused
not yet
Adjust
Figure 2. Two techniques for a focus ring. Tab through the samples, or press Focus next to move a real :focus-visible state between them, and compare the two techniques. Rauno Freiberg prefers to create focus rings with a shadow: two stacked box-shadows fake the padding and the ring, so the shape always matches the element's own corner radius. Outline and outline-offset can do the same job, but Safari did not adhere to an element's radius until Safari 16.4, an update tied to the macOS version, and an outline ring is not clipped if it overflows a container the way a box-shadow ring can be when that container sets overflow:hidden. The link has no background at rest, so its radius stays invisible until it is focused. Turn on Link trick for his other habit: a 2px radius, 2px of padding, and a negative margin that cancels it.Illustrative numbers

Quote marks, data attributes, underlines#

Two more from Rauno: testimonial quote marks set in Georgia rather than Inter, a detail from the Radix UI site, hung with text-indent: -0.4em (credited to Shu); and styling against a data-variant attribute instead of mapping variants to class names. Neither shows in a screenshot.

Paco Coursey’s Custom text underlines (2020) sands a single line. With text-decoration: underline giving too little control while the CSS Text Decoration Module was pending, he draws the line as a linear-gradient background. Move it with background-position (left 1.05em), thicken it with the height (100% 0.25em), hide it around descenders with a text-shadow in the background colour (and text-shadow: none in ::selection), dash it with a repeating-linear-gradient sized 1ch, the width of the zero glyph. It wraps across lines.

CSSPaco Coursey, Custom text underlines
background-image: linear-gradient(gray, gray);background-size: 100% 1px;background-position: left bottom;background-repeat: no-repeat;text-shadow: 0.1em 0 var(--background), -0.1em 0 var(--background);

His px vs rem in font-size (2022) turns the same care on a habit: since nearly every site hard-codes a size on html or uses px, “when browser scaling is ignored, there’s no a11y reason to use rem over px.” The unit is not the virtue; respecting the reader’s setting is.

Good for who#

Sanding has a direction, from Jim’s Good Design (2022). Design is about intent, so ask: good for who? An unsubscribe button that dodges the cursor is good for whoever wants you subscribed and bad for you. Dribbble shots may be good design if the intent is likes, but “It’s hard to know whether a static picture depicting dynamic software helps a real-world human achieve a particular goal.” Where owner and user diverge, state a priority of constituencies.

So decide who you are sanding for, then use the thing the way they will, through every entry and exit. The agonizing experience is made of the splinters you skipped.