CSS Form Controls
Form controls need to be easy to read and operate with a mouse, keyboard, or touch screen. CSS can give them a consistent appearance while keeping their built-in behavior.
Style text fields consistently
Start with a visible label for each control. Use a class for shared field styles so checkboxes, file inputs, and buttons do not accidentally inherit text-field sizing.
<form class="contact-form"> <div class="field"> <label for="email">Email address</label> <input class="text-control" id="email" name="email" type="email" required /> </div>
<div class="field"> <label for="message">Message</label> <textarea class="text-control" id="message" name="message" rows="5"></textarea> </div>
<button class="submit-button" type="submit">Send message</button></form>.contact-form { max-width: 32rem; display: grid; gap: 1.25rem;}
.field { display: grid; gap: 0.4rem;}
.text-control { box-sizing: border-box; width: 100%; min-height: 2.75rem; padding: 0.65rem 0.75rem; border: 1px solid #64748b; border-radius: 0.4rem; background: #fff; color: #0f172a; font: inherit;}
textarea.text-control { resize: vertical;}font: inherit helps native controls match the surrounding text. box-sizing: border-box keeps a width: 100% field inside its container after padding and borders are added.
Keep focus visible
People using a keyboard need a clear sign of which control is active. A text field can show a focus ring on focus; a button can use :focus-visible so keyboard focus is clear without showing the ring after every pointer click.
.text-control:focus { outline: 3px solid #2563eb; outline-offset: 2px;}
.submit-button:focus-visible { outline: 3px solid #2563eb; outline-offset: 3px;}Do not remove the browser’s default outline unless you replace it with an equally visible focus style. See CSS Accessibility for more keyboard and contrast guidance.
Style selection controls
accent-color changes the accent of native checkboxes and radio buttons without rebuilding them from scratch.
<label class="choice"> <input type="checkbox" name="updates" /> Email me occasional updates</label>.choice { display: flex; align-items: start; gap: 0.6rem;}
.choice input { width: 1.2rem; height: 1.2rem; accent-color: #1d4ed8;}The label text is clickable because the input is inside the <label> element. Keep the native checkbox so it retains keyboard and assistive technology behavior.
Show errors and disabled states
Use :invalid to style a field that fails HTML validation. A required empty field can match :invalid even before the user submits the form, so decide when to reveal any error message in the form’s behavior as well as its CSS.
.text-control:invalid { border-color: #b91c1c;}
.text-control:disabled,.submit-button:disabled { opacity: 0.6; cursor: not-allowed;}Pair an error color with a text message that explains the problem. Color alone does not tell every visitor what needs fixing.
Common mistakes
- Using a placeholder as the only label. It disappears when the user types and may not explain the field clearly.
- Removing outlines without adding a visible focus style.
- Applying text-input styles to every
inputtype, including checkboxes and file inputs. - Relying only on red borders to communicate validation errors.
- Disabling a submit button without explaining why the form cannot be submitted.
Further reading
See MDN’s form styling guide for native control behavior and additional examples.