uxskill
Star on GitHub
Language
English 简体中文 繁體中文 日本語 한국어 हिन्दी Bahasa Indonesia Tiếng Việt ไทย العربية Español Français Deutsch Português Русский Türkçe Italiano

## The icon tell

Iconography has a fingerprint as legible as the font choice. A few patterns show up in nearly every generated interface:

- One library, picked by popularity (Heroicons or Lucide) at a single 1.5px or 2px stroke, never tuned to the brand.
- An icon per feature card, decorative rather than functional, so the eye learns to skip them.
- The same dozen shapes recycled across unrelated products: a generic bolt for speed, a shield for security, a rocket for launch.
- Worst case, emoji standing in for UI icons (a rocket glyph, a sparkle, a checkmark face) pasted straight into a button or a list.

The first three are merely generic. The last is the one that costs you, and it costs you twice.

## Why it ships

The model reaches for whatever it has seen most. Heroicons and Lucide dominate the open component demos it trained on, so they are the path of least resistance: the icon-shaped point at the center of the distribution. Gluing one icon to every heading is the same reflex: a template fills a slot, and an empty slot feels wrong, so it gets filled regardless of whether the icon adds meaning.

Emoji are a different failure with the same root. They are zero-effort: already in the text stream, no import, no SVG. So when a quick mock needs a visual marker, an emoji lands there. The trouble is that an emoji is not a UI asset. It is a font glyph the operating system renders, and that has consequences.

> An emoji icon is the one design choice that looks different on every device you ship to. You drew nothing. You handed the rendering to Apple, Google, and Microsoft, and they each answer differently.

On Apple platforms it is a glossy full-color picture; on Android, a flatter Material shape; on older Windows, a hollow outline or a blank box. Your "icon" is three icons you never approved. It also reads as unfinished: a placeholder marker, the kind you leave in a draft and mean to swap. Worse, screen readers announce the emoji's full Unicode name aloud, which is rarely the label you wanted, so the accessibility story breaks alongside the visual one.

## The fix: pick a family, use it with intent

Two moves cover most of the gap. First, choose an icon family whose weight matches the brand instead of accepting the default. A serious, dense product wants a thinner, sharper set; a warm consumer product can carry a rounded, filled one. Heroicons, Lucide, and Phosphor each ship multiple weights. The point is that the weight is a decision, made once, and held across the interface.

Second, use icons sparingly. An icon should mark an action or a category the user navigates by, not garnish a heading. Most marketing sections read better with no icon at all than with a decorative one per row. When you do use them, keep the stroke weight and the optical size consistent, and never mix two libraries. Two stroke languages in one screen is its own tell.

the icon tell | why it ships | the fix
--- | --- | ---
Default library at one weight | Most-seen set, lowest friction | Pick a family whose weight fits the brand
One icon per heading | A template slot that feels wrong empty | Use icons only where they aid navigation
Two libraries mixed | Grabbed whatever was nearest | One family, one stroke weight, throughout
Emoji as a UI icon | Zero-effort, already in the text | Real SVG icon with a label; never an emoji

And the non-negotiable: no emoji as interface icons, ever. They render differently per platform, read as a placeholder, and break for assistive tech. If a visual marker is worth shipping, it is worth a real SVG you control.

## How ux-skill keeps it honest

Three parts of the engine pull against the default. The components manifest carries icon guidance per component (what an icon is for in a button, a nav item, an empty state, and where it does not belong) so the recommendation is "use a marked action icon here," not "drop a bolt on each card." The 72 brand specs show how real brands handle iconography: which family, which weight, how restrained, so you can match a reference instead of inheriting the centroid. And the anti-slop linter flags emoji used as icons directly: a glyph inside a button, a list item, or a class named `icon` trips a high-severity rule, the same way it flags a violet gradient or Inter set at display size.

The effect is that the icon question gets answered on purpose. Same brief, run again next week, on a different machine: identical guidance. Deterministic, offline, no model in the loop.

## The point

Generated interfaces use the same icons because the model defaults to the most-seen library, fills every slot on reflex, and treats emoji as a free substitute. Decide the family by brand weight, use icons only where they carry meaning, hold one stroke language across the screen, and keep emoji out of the UI entirely. The icons stop being a tell and start being a system.

    pip install uxskill
    # then, in your AI coding tool:
    # /ux-recommend  : icon guidance per component; or `uxskill lint` to catch emoji-as-icon

## Related

- The Inter tell
- The full list of AI design tells
- The centroid problem
- The anti-pattern catalogue