A good-looking form that people cannot use is a failure. These are the points that matter most, and almost all of them are CSS or HTML you already know.
1. Real labels, always visible
Every field needs a <label for>. Do not use a placeholder as the only label, because it disappears when typing and has weak contrast.
2. Enough contrast
- Text: 4.5 : 1.
- Field borders and focus rings: 3 : 1 against the background.
3. Visible focus on every control
Use :focus-visible with a clear outline. See Form Focus States.
4. Large touch targets
Inputs and buttons should be at least about 44px tall. Make labels clickable so checkbox and radio targets are bigger.
5. Errors in words, tied to the field
Use text next to the field, an icon and aria-describedby. Not only a red border.
6. Respect zoom and font settings
Use rem for font size and em for padding. Do not set maximum-scale in the viewport tag. On iPhones, inputs with a font smaller than 16px cause Safari to zoom in when focused, so keep input text at 1rem or larger.
<style>
form { max-width: 320px; font-family: system-ui, sans-serif; }
.row { margin-bottom: 14px; }
label { display: block; font-weight: 600; margin-bottom: 4px; }
input { width: 100%; box-sizing: border-box; min-height: 44px; padding: 8px 12px; font: inherit; font-size: 1rem; border: 2px solid #6b6560; border-radius: 6px; }
input:focus-visible { outline: 3px solid #1a5276; outline-offset: 2px; }
.hint { font-size: .875rem; color: #4a4540; margin-top: 4px; }
button { min-height: 44px; padding: 0 24px; font: inherit; font-weight: 600; background: #1a5276; color: #fff; border: 0; border-radius: 6px; }
</style>
<form>
<div class="row"><label for="a">Full name</label><input id="a" autocomplete="name"></div>
<div class="row"><label for="b">Email</label><input id="b" type="email" autocomplete="email" aria-describedby="bh"><p id="bh" class="hint">We only use it to send your receipt.</p></div>
<button type="submit">Place order</button>
</form>
7. Group related fields
Wrap radio buttons and related fields in <fieldset> with a <legend>, which gives screen reader users the group’s name.
Exercise: spot the problems
A form uses placeholder text instead of labels, grey #bbb borders, outline: none on all inputs and a red border as the only error signal. List four fixes.
Show a possible solution
- Add real
<label>elements. 2. Darken the borders to at least 3:1 contrast. 3. Replaceoutline: nonewith a visible:focus-visiblestyle. 4. Add an error message in text, linked witharia-describedby.