CSS Forms

HTML forms collect information from users — names, passwords, messages, selections. Without CSS, form elements look plain and inconsistent across browsers. With CSS, you transform them into polished, accessible, and branded inputs that feel part of your design.

Default Form Elements Look Different on Every Browser

DIAGRAM — Same HTML, different browsers:

Chrome:    [ text input with square corners ]
Safari:    [ text input with slightly rounded corners ]
Firefox:   [ text input with slightly different padding ]
Edge:      [ text input with different border color ]

CSS resets this inconsistency and gives you full control.

Styling Text Inputs and Textareas

input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
textarea {
  width: 100%;
  padding: 10px 14px;
  border: 1px solid #ccc;
  border-radius: 6px;
  font-size: 1rem;
  font-family: inherit;  /* important — inputs don't inherit fonts by default */
  color: #333;
  background: #fff;
  box-sizing: border-box;
  outline: none;
  transition: border-color 0.2s;
}

input:focus,
textarea:focus {
  border-color: #3498db;
  box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
}

Why font-family: inherit Matters

By default, browsers render form inputs with a different font than the rest of the page. Setting font-family: inherit makes inputs use the same font as their parent, keeping your typography consistent.

DIAGRAM — Without and with font inheritance:

Without font-family: inherit:
  Page text:  "Hello" in Roboto
  Input text: "Hello" in Times New Roman ← jarring mismatch

With font-family: inherit:
  Page text:  "Hello" in Roboto
  Input text: "Hello" in Roboto ← consistent

Styling Labels

label {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  color: #555;
  margin-bottom: 6px;
}

Full Form Layout Example

<form>
  <div class="form-group">
    <label for="name">Full Name</label>
    <input type="text" id="name" placeholder="Jane Doe">
  </div>
  <div class="form-group">
    <label for="email">Email</label>
    <input type="email" id="email" placeholder="jane@example.com">
  </div>
  <button type="submit">Submit</button>
</form>

.form-group {
  margin-bottom: 20px;
}
DIAGRAM — Styled form layout:

┌────────────────────────────────┐
│ Full Name                      │  ← label
│ ┌──────────────────────────┐   │
│ │ Jane Doe                 │   │  ← input
│ └──────────────────────────┘   │
│                                │
│ Email                          │
│ ┌──────────────────────────┐   │
│ │ jane@example.com         │   │
│ └──────────────────────────┘   │
│                                │
│ [ Submit ]                     │
└────────────────────────────────┘

Styling Select Dropdowns

Select elements are the hardest to style because each browser renders them differently. Use appearance: none to strip the default styling and apply your own.

select {
  width: 100%;
  padding: 10px 14px;
  border: 1px solid #ccc;
  border-radius: 6px;
  font-size: 1rem;
  font-family: inherit;
  background-color: #fff;
  background-image: url("data:image/svg+xml,..."); /* custom arrow icon */
  background-repeat: no-repeat;
  background-position: right 12px center;
  appearance: none;         /* remove browser default styling */
  -webkit-appearance: none;
  cursor: pointer;
}

Styling Checkboxes and Radio Buttons

Default checkboxes and radio buttons are very hard to style directly. The modern approach uses accent-color for a quick color fix, or visually hides the default control and builds a custom one using ::before.

Quick Method — accent-color

input[type="checkbox"],
input[type="radio"] {
  accent-color: #3498db;
  width: 18px;
  height: 18px;
  cursor: pointer;
}

accent-color changes the theme color of the built-in control without replacing it.

Custom Checkbox

/* Hide default checkbox */
.custom-check input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

/* Custom box */
.custom-check label {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}

.custom-check label::before {
  content: "";
  display: inline-block;
  width: 20px;
  height: 20px;
  border: 2px solid #ccc;
  border-radius: 4px;
  flex-shrink: 0;
}

/* When checked — change the ::before appearance */
.custom-check input:checked + label::before {
  background: #3498db;
  border-color: #3498db;
  background-image: url("checkmark-icon");
}

Placeholder Text Styling

input::placeholder {
  color: #aaa;
  font-style: italic;
  font-size: 0.9rem;
}

/* Firefox needs this */
input::-moz-placeholder {
  color: #aaa;
}

Validation State Styling

/* Valid input (passed HTML5 validation) */
input:valid {
  border-color: #27ae60;
}

/* Invalid input */
input:invalid {
  border-color: #e74c3c;
}

/* Only show validation after the user has interacted */
input:not(:placeholder-shown):valid {
  border-color: #27ae60;
}

input:not(:placeholder-shown):invalid {
  border-color: #e74c3c;
}

Disabled Form Fields

input:disabled,
select:disabled,
textarea:disabled {
  background: #f5f5f5;
  color: #999;
  cursor: not-allowed;
  border-color: #ddd;
  opacity: 0.7;
}

Read-Only Fields

input:read-only {
  background: #f9f9f9;
  border-color: #ddd;
  color: #666;
}

Required Field Indicator

/* Add a red asterisk after required labels */
label.required::after {
  content: " *";
  color: #e74c3c;
}

/* Or target by sibling — label after a required input */
input:required + label::after {
  content: " *";
  color: red;
}

Form Accessibility Notes

  • Always pair a <label> with every input using for and id attributes. Screen readers depend on this.
  • Never remove :focus styles without replacing them. Keyboard users cannot navigate without visible focus indicators.
  • Use sufficient color contrast (at least 4.5:1 ratio) for placeholder and label text.
  • Ensure error messages are visible — don't rely on color alone to indicate errors.

Well-styled forms reduce friction for users. Inputs that are clearly focused, validation that responds clearly, and labels that are always readable — these small details make the difference between a form users trust and one they abandon.

Leave a Comment

Your email address will not be published. Required fields are marked *