Form State Pseudo-classes
Form pseudo-classes let you style inputs based on their validity, state, and user interaction — :valid, :invalid, :checked, :disabled, :required, :placeholder-shown. Build form validation UIs without JavaScript.
Form Pseudo-classes
- :valid / :invalid — Based on HTML validation (required, pattern, type='email')
- :checked — For checked checkboxes and radio buttons. Style the label based on checked state
- :disabled / :enabled — Style disabled form fields differently (opacity, cursor)
- :required / :optional — Target required vs optional fields
- :placeholder-shown — Input still showing placeholder (user hasn't typed). Useful for floating labels
- :focus-within — Parent is styled when ANY child has focus. Great for form groups
- :in-range / :out-of-range — For number inputs with min/max attributes
Form States Code
/* Valid/invalid input styling */
input:valid { border-color: #2ecc71; }
input:invalid:not(:placeholder-shown) {
border-color: #e74c3c;
/* Only show red AFTER user has typed (not on page load) */
}
/* Checked checkbox label */
input[type="checkbox"]:checked + label {
color: #2ecc71;
text-decoration: line-through;
}
/* Disabled state */
input:disabled, button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Focus-within: highlight form group */
.form-group:focus-within {
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
}
/* Floating label pattern */
.float-label input:not(:placeholder-shown) + label,
.float-label input:focus + label {
transform: translateY(-24px) scale(0.85);
color: #667eea;
}Tip
The :not(:placeholder-shown) trick is essential: input:invalid:not(:placeholder-shown) only shows red borders AFTER the user has typed something invalid. Without it, empty required inputs show red borders on page load.
Selectors target HTML elements for styling
Common Mistake
Styling :invalid without guarding against empty-state. On page load, every required input is :invalid. Users see red borders before they've interacted. Always combine :invalid with :not(:placeholder-shown).
Practice Task
Build CSS-only form validation: (1) input:valid gets green border, (2) input:invalid:not(:placeholder-shown) gets red border, (3) .form-group:focus-within gets blue glow, (4) input:disabled gets opacity: 0.5, (5) Floating label with :not(:placeholder-shown).
Quick Quiz
Key Takeaways
- Form pseudo-classes let you style inputs based on their validity, state, and user interaction — :valid, :invalid, :checked, :disabled, :required, :placeholder-shown.
- :valid / :invalid — Based on HTML validation (required, pattern, type='email')
- :checked — For checked checkboxes and radio buttons. Style the label based on checked state
- :disabled / :enabled — Style disabled form fields differently (opacity, cursor)