Skip to content
DERKONLINE

Build Visual Pickers Users Can See, Not Name Lists

Swatch grids, font previews, and icon tiles that let people choose by sight instead of decoding library identifiers.

Derrick S. K. Siawor7 min read

Open the settings page of a half-built admin panel and you will find it: a dropdown asking the user to choose an icon, with options that read "Phone," "MessageCircle," "FileDown," "ChevronRight." The user wants the chat bubble. They have to know that the chat bubble is called "MessageCircle" in some library they have never heard of, mentally translate the name back into the shape, and hope they guessed right. They are doing the UI's job for it, and the UI is making them feel stupid for a choice that should have been a glance.

This is one of the most common and most fixable failures in admin interfaces. Whenever a user is choosing something visual, an icon, a color, a font, a theme, a layout, the picker must render the actual visual thing. A list of names or identifiers for a visual choice forces a translation that the interface exists specifically to perform. The fix is not subtle and it is not expensive. It is the difference between a tool that feels considered and a tool that feels like the developer ran out of time at the part the user actually touches.

Why naming a visual choice is the wrong default

The reason this pattern is so common is that it is the path of least resistance for the developer. The data is already a list of strings, a <select> over those strings is two minutes of work, and from the developer's chair it looks done. The developer knows that "MessageCircle" is the chat bubble because they have the library's documentation open. The user does not.

That gap is the whole problem. A <select> of icon names asks the user to carry information they do not have. It fails for the non-developer operator who has never seen a Lucide or Heroicons name in their life. It fails for the non-English user for whom the identifier is doubly opaque. It fails for anyone who simply wants to see the thing before they pick it, which is everyone, because that is how humans choose visual things. We point at what we want. We do not recite its internal name.

The same failure shows up everywhere visual choices live. A color picker offering "champagne," "obsidian," and "warm-stone" as text options. A font selector listing "Marcellus," "Montserrat," "Inter" with no preview. A theme chooser with radio buttons labeled "cream" and "ivory," which is its own trap if you have not built real dark mode that is not just an inverted color sheet. In every case the user is being asked to decode an identifier instead of seeing a choice, and in every case the fix is to show the visual.

What a visual picker actually looks like

The pattern is consistent across every kind of visual choice, and it comes down to rendering the thing and letting the user click it.

  • Icon picker. A grid of clickable tiles, each rendering the actual icon at a usable size, with a small label below for accessibility and keyboard use. The user sees the chat bubble, clicks it, done. The selected tile gets a clearly different state, a ring or a brighter background, so the active choice reads instantly.
  • Color picker. A grid of swatches rendered in the actual colors, not their names. The user sees champagne next to obsidian and picks by eye. The selected swatch is ringed, and the palette behind it should already hit WCAG contrast on every screen without wrecking your brand so no choice the user makes lands on an unreadable pairing.
  • Font picker. Each option renders a sample phrase set in that actual font, so the user reads the typeface instead of guessing what "Marcellus" looks like.
  • Theme or layout picker. Mini-mockup previews showing what each option produces, rather than radio buttons labeled with internal names. The user sees the layout, not the word for it.

The implementation details that make these feel finished are small but real. Each tile is a real button element so it gets native focus and keyboard support, with arrow-key navigation across the grid. When the catalog is large, a search field filters it live and the grid scrolls within a bounded height so a hundred options do not take over the page. A tiny label under each tile carries the identifier for screen readers and keyboard users, but the visual is the primary affordance and the label is secondary. None of this is hard. It is just more than two minutes, which is exactly why the lazy default wins so often.

Scale is part of the design, not an afterthought

A visual picker that works at three options can fall over at a hundred. If a font picker renders every option in its own typeface and an operator has uploaded eighty fonts, opening that picker naively downloads eighty font files at once. If an icon grid renders every icon in a fifteen-hundred-icon library on mount, the page stalls. The visual picker has to be built to stay fast as the catalog grows, which means lazy-loading previews as they scroll into view, paginating or virtualizing long grids, and loading only the handful of visuals actually on screen rather than all of them.

This is the same discipline that should apply to any list or grid that could grow: design for the case where there are far more items than you expect, because a picker that is fine at ten and melts at five hundred is a bug waiting for a real user to find it. Lazy-loading those font and image previews is also a third-party and asset performance budget question, since loading eighty fonts on open is exactly the kind of weight that quietly wrecks page speed. The selection itself should also feel alive, which is where micro-interactions that separate a premium product from a prototype earn their keep, while staying inside what users who get sick from motion need you to respect. The right time to build the bounded version is the first time, not after someone hits the wall.

Why this is a respect-for-the-user decision

It is tempting to file visual pickers under polish, the kind of thing you do later if there is time. That framing is wrong. A naming-based picker for a visual choice is not unpolished, it is broken, because it makes the user do work the interface was supposed to do. Every time someone has to translate "FileDown" into the shape of a file with a down arrow, the product is telling them it did not care enough to show them. It is the same kind of unforced friction as a vague error message, which is why writing error messages that recover trust instead of losing customers belongs to the same design instinct. Multiply that across an admin surface full of visual choices and you have a tool that constantly makes its operators feel like they are fighting it.

The teams that build admin surfaces people actually like to use treat visual pickers as a baseline, not a luxury. This instinct, that the interface should do the visual translation for the user rather than making the user do it, runs through everything we build, and it is exactly the kind of detail we obsess over when designing the websites and web apps our clients ship. It is the same care that turns a dead screen into an empty state that drives action instead of a place the operator gets stuck. An admin panel is a product too, used every day by the people running the business, and it deserves the same care as the customer-facing front end.

The rule, and the test that enforces it

The rule is simple enough to apply without thinking: any time you find yourself writing a <select> or a list of names for a visual choice, stop, and build the grid that renders the actual visuals instead. Icon, color, font, theme, layout, image, emoji, any choice the user makes with their eyes, the picker shows it.

The test that catches the violation is equally simple. Look at any choice in your admin interface and ask whether the user is picking something visual. If they are, ask whether the picker shows that visual or names it. If it names it, you have the bug, and the user is doing your interface's job. The fix takes an afternoon and changes the entire feel of the surface, from a tool that makes people decode identifiers into a tool that lets them point at what they want and click. That is what an interface is for.