Skip to main content
Syllabus
On this page

HTML and CSS Forms and Inputs: Styled, Accessible and Validated Form Controls

Badar KhalilUpdated September 30, 2026 6 min read

Why forms and inputs matter

Forms and inputs are how users log in, search, pay, sign up and send data. A poorly built form loses users, while a clear, accessible, well-validated form increases conversions. Modern HTML and CSS give you powerful tools so you can build great forms with less JavaScript.

Focus keyword: CSS forms and inputs. Related trending keywords: accessible form design, :user-invalid, :focus-visible, accent-color, field-sizing: content, CSS toggle switch, floating label CSS, HTML form validation, autocomplete attribute.

Start with correct HTML

  • Every control needs a visible <label for='id'> linked to the input. Placeholders are not labels because they disappear and often have low contrast.
  • Use the right type: email, tel, url, number, date, search, password. This gives the right mobile keyboard and built-in validation.
  • Add autocomplete tokens such as name, email, username, new-password, one-time-code, street-address. It helps users and is a WCAG requirement for common data.
  • Use inputmode (for example numeric) when you need a specific keyboard without changing the type.
  • Group related controls with <fieldset> and <legend>, especially radio buttons and checkboxes.

Base input styling

Set font: inherit (controls do not inherit fonts by default), a minimum height of about 44px, padding, a visible border with at least 3:1 contrast against the background, and a clear :focus-visible state. Use box-sizing: border-box and width: 100% with a max width. Keep font size at 16px or larger on mobile so iOS does not zoom in on focus.

Validation with HTML and CSS

  • Built-in attributes: required, minlength, maxlength, min, max, pattern, step.
  • :invalid matches immediately, even before the user types, which shows red borders too early. Prefer :user-invalid and :user-valid, which only match after the user has interacted with the field.
  • Show error text near the field and connect it with aria-describedby. Mark invalid fields with aria-invalid='true' when you control validation in JavaScript.
  • Do not use color alone. Add an icon or text such as Enter a valid email address.
  • The Constraint Validation API (input.validity, setCustomValidity(), reportValidity()) lets you customize messages.

Helpful modern CSS for forms

  • accent-color: change the color of native checkboxes, radios, range and progress with one line.
  • field-sizing: content: lets textareas and inputs grow with their content (check browser support and provide fallback rows).
  • :has(): style a field wrapper when it contains an invalid input or a checked checkbox, for example .field:has(:user-invalid).
  • :placeholder-shown: detect an empty field to build floating labels.
  • appearance: none: remove native styling to build custom switches, checkboxes and selects. Keep the real input in the DOM so it stays accessible.
  • color-scheme and light-dark(): make controls follow the theme.

Custom checkbox and switch

Keep the native input and style it with appearance: none, or hide it visually (not with display: none) and style a sibling. For a toggle switch use <input type='checkbox' role='switch'> so screen readers announce it as a switch.

Floating labels

A floating label sits inside the input and moves up when the field is focused or filled. Use placeholder=' ' and the selector input:not(:placeholder-shown) + label. Make sure the label stays readable and does not overlap the text.

Layout and usability

  • Use a single column for most forms. Use CSS grid for small related groups (city and ZIP).
  • Put hints below the label, not inside the placeholder.
  • Mark required fields consistently and explain the marker.
  • Disable the submit button only if you explain why. Usually show errors on submit instead.
  • Keep touch targets large, and do not break paste in password fields.

Quick summary

Combine semantic labels, the right input types and autocomplete, clear focus and error states, and modern CSS like :user-invalid, accent-color and :has() to create accessible CSS forms and inputs.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Exercise: Create an accessible validated signup fieldHTML

Style the email input. It needs a visible label, a hint linked with aria-describedby, a clear focus-visible style, and validation styling that only appears after interaction using :user-invalid. Show an error message next to the field using :has() without relying on color alone.

Try it Yourself HTML
Output

Press Run to execute.

Show expected output
After typing an invalid email and leaving the field, the input shows a red border and the error text appears. Before interaction, nothing is shown in red.

This is a self-check — compare your result with the expected output above.

Was this page helpful?