UI/UX law

// Perception & Gestalt;

Input Affixes

A prefix or suffix attached to an input (a currency symbol, a fixed protocol string, a unit) is part of that field, not a label sitting beside it, so the border, background, and focus ring belong to the wrapper around all three pieces, never to the inner <input> alone.

Mechanism

Why it happens

Give the <input> its own border and the affix its own box, and focusing the field only highlights the typed value; the $ or https:// sits just outside the ring, reading as a separate, unrelated element bolted onto the side of the real control. Move the border, background, and border-radius to the wrapper instead, strip the input completely bare (border: 0, outline: 0, background: transparent), and the affix and the input become one uninterrupted surface with nothing left to visually seam them. :focus-within finishes it: bound to the wrapper rather than :focus on the input, it fires whenever the input inside gains focus, so the ring appears around the whole group at once instead of carving out just the typed portion.

Impact

Why it matters

  • A ring or border scoped to the bare <input> excludes the affix from the focus state, so the $ or https:// looks like a static label the field forgot to include
  • The visual seam between affix and input reads as a boundary between two controls, even though only one value is ever entered
  • Padding, font size, and vertical alignment that drift between the affix and the input become obvious the moment either is styled on its own instead of inheriting the wrapper's rhythm
  • :focus on the input alone can't reach a sibling affix; only :focus-within on the shared wrapper lets one focus event style the whole compound field

Example

Without vs. with

Without
$
1,250.00

↳ the ring hugs only the typed value, $ sits outside it

A "Website" field puts the border and focus ring on the bare <input>; "https://" sits in an unstyled span to its left, so clicking into the field highlights only the typed part while the prefix stays visually detached, looking like a stray label.

With
$1,250.00

↳ the ring wraps the whole group, prefix included

The same field wraps "https://" and the input in one bordered container with the input stripped completely bare; focusing the input triggers :focus-within on the wrapper, so the whole group, prefix included, lights up as a single field.

Checklist

How to apply it

Put the border, background, and border-radius on the wrapper element, never on the inner <input>

Strip the input itself bare — border: 0, outline: 0, background: transparent — so it shows only the wrapper's surface behind it

Style :focus-within on the wrapper (border-color plus a soft box-shadow ring), not :focus on the input, so focusing the field highlights the affix along with it

Match the affix's padding and line-height to the input's so both sit on the same baseline with no visible offset between them

Make a purely decorative affix non-interactive (a <span>, not a button) so it doesn't intercept clicks meant for the input

Recipe

Code example

Where it shows up

Element areas

Forms