CSS Form Pseudo-classes ๐
Style form elements based on their state, validity, and user interaction without JavaScript.
What are Form Pseudo-classes?
Form pseudo-classes are CSS selectors that allow you to style form elements based on their current state, validity, and user interaction. They provide powerful ways to create interactive and user-friendly forms with immediate visual feedback.
๐ฏ State-based Styling
Style elements based on :focus, :checked, :disabled states
โ Validation Feedback
Provide instant visual feedback with :valid and :invalid
โก No JavaScript Required
Create interactive forms with pure CSS
Basic Form Pseudo-classes
Essential Pseudo-classes:
- :focus - Styles when element is focused
- :valid / :invalid - Based on input validation
- :required / :optional - For required fields
- :disabled / :enabled - For disabled state
- :read-only / :read-write - For editable state
Basic Form Pseudo-classes Implementation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Basic Form Pseudo-classes</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 3rem;
color: white;
}
.header h1 {
font-size: 3rem;
margin-bottom: 1rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.form-container {
background: white;
border-radius: 15px;
padding: 2rem;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.form-group {
margin-bottom: 2rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: #2c3e50;
}
.form-control {
width: 100%;
padding: 1rem;
border: 2px solid #bdc3c7;
border-radius: 8px;
font-size: 1rem;
transition: all 0.3s ease;
}
/* :focus pseudo-class */
.form-control:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
transform: translateY(-2px);
}
/* :required pseudo-class */
.form-control:required {
border-left: 4px solid #e74c3c;
}
.form-control:required:valid {
border-left-color: #2ecc71;
}
/* :optional pseudo-class */
.form-control:optional {
background-color: #f8f9fa;
}
/* :valid and :invalid pseudo-classes */
.form-control:valid {
border-color: #2ecc71;
background-color: rgba(46, 204, 113, 0.05);
}
.form-control:invalid {
border-color: #e74c3c;
background-color: rgba(231, 76, 60, 0.05);
}
/* :disabled pseudo-class */
.form-control:disabled {
background-color: #ecf0f1;
color: #95a5a6;
cursor: not-allowed;
opacity: 0.6;
}
/* :read-only pseudo-class */
.form-control:read-only {
background-color: #fff3cd;
border-color: #ffeaa7;
color: #856404;
}
.demo-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-top: 2rem;
}
.demo-item {
padding: 1rem;
border-radius: 8px;
background: #f8f9fa;
}
.code-example {
background: #2c3e50;
color: white;
padding: 1rem;
border-radius: 10px;
margin-top: 1rem;
font-family: monospace;
font-size: 0.9rem;
}
.status-indicator {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 0.5rem;
}
.status-valid { background: #2ecc71; }
.status-invalid { background: #e74c3c; }
.status-optional { background: #3498db; }
.status-required { background: #f39c12; }
@media (max-width: 768px) {
.demo-grid {
grid-template-columns: 1fr;
}
.header h1 {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>๐ฏ Form Pseudo-classes</h1>
<p>Style form elements based on their state</p>
</div>
<div class="form-container">
<form id="demoForm">
<div class="form-group">
<label for="email">Email Address <span class="status-required status-indicator"></span>Required</label>
<input type="email" id="email" class="form-control" placeholder="Enter your email" required>
<div class="code-example">
input:required { border-left: 4px solid #e74c3c; }
input:required:valid { border-left-color: #2ecc71; }
</div>
</div>
<div class="form-group">
<label for="name">Full Name <span class="status-optional status-indicator"></span>Optional</label>
<input type="text" id="name" class="form-control" placeholder="Enter your name">
<div class="code-example">
input:optional { background-color: #f8f9fa; }
</div>
</div>
<div class="form-group">
<label for="password">Password <span class="status-required status-indicator"></span>Required</label>
<input type="password" id="password" class="form-control" placeholder="Enter password" required minlength="6">
<div class="code-example">
input:valid { border-color: #2ecc71; }
input:invalid { border-color: #e74c3c; }
</div>
</div>
<div class="demo-grid">
<div class="demo-item">
<label for="disabledInput">Disabled Field</label>
<input type="text" id="disabledInput" class="form-control" value="This field is disabled" disabled>
<div class="code-example">
input:disabled {
background-color: #ecf0f1;
cursor: not-allowed;
}
</div>
</div>
<div class="demo-item">
<label for="readonlyInput">Read-only Field</label>
<input type="text" id="readonlyInput" class="form-control" value="This field is read-only" readonly>
<div class="code-example">
input:read-only {
background-color: #fff3cd;
border-color: #ffeaa7;
}
</div>
</div>
</div>
<div class="form-group">
<label for="url">Website URL</label>
<input type="url" id="url" class="form-control" placeholder="https://example.com">
<div class="code-example">
input:focus {
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
</div>
</div>
</form>
<div style="margin-top: 2rem; padding: 1rem; background: #e8f4fd; border-radius: 8px;">
<h3>๐ก Interactive Demo</h3>
<p>Try interacting with the form fields to see the different states:</p>
<ul>
<li><span class="status-valid status-indicator"></span> Focus on fields to see :focus styles</li>
<li><span class="status-invalid status-indicator"></span> Enter invalid data to see :invalid styles</li>
<li><span class="status-required status-indicator"></span> Required fields have special indicators</li>
</ul>
</div>
</div>
</div>
</body>
</html>Advanced Form Pseudo-classes
Input Validation
Use :in-range, :out-of-range, and :placeholder-shown for advanced validation states.
Custom Controls
Create custom checkboxes, radio buttons, and selects using :checked and :indeterminate.
Advanced Form Pseudo-classes Implementation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced Form Pseudo-classes</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 3rem;
color: white;
}
.header h1 {
font-size: 3rem;
margin-bottom: 1rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.form-container {
background: white;
border-radius: 15px;
padding: 2rem;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.form-group {
margin-bottom: 2rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: #2c3e50;
}
/* :in-range and :out-of-range */
.range-input {
width: 100%;
padding: 1rem;
border: 2px solid #bdc3c7;
border-radius: 8px;
font-size: 1rem;
}
.range-input:in-range {
border-color: #2ecc71;
background-color: rgba(46, 204, 113, 0.05);
}
.range-input:out-of-range {
border-color: #e74c3c;
background-color: rgba(231, 76, 60, 0.05);
}
/* :checked for checkboxes and radio buttons */
.checkbox-group, .radio-group {
display: flex;
gap: 1rem;
flex-wrap: wrap;
margin: 1rem 0;
}
.custom-checkbox, .custom-radio {
position: relative;
padding-left: 2rem;
cursor: pointer;
}
.custom-checkbox input, .custom-radio input {
position: absolute;
opacity: 0;
}
.checkmark {
position: absolute;
left: 0;
top: 0;
height: 1.5rem;
width: 1.5rem;
background: #ecf0f1;
border: 2px solid #bdc3c7;
border-radius: 4px;
transition: all 0.3s ease;
}
.custom-checkbox input:checked ~ .checkmark {
background: #3498db;
border-color: #3498db;
}
.custom-checkbox input:checked ~ .checkmark::after {
content: "โ";
position: absolute;
color: white;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.radiomark {
position: absolute;
left: 0;
top: 0;
height: 1.5rem;
width: 1.5rem;
background: #ecf0f1;
border: 2px solid #bdc3c7;
border-radius: 50%;
transition: all 0.3s ease;
}
.custom-radio input:checked ~ .radiomark {
border-color: #9b59b6;
}
.custom-radio input:checked ~ .radiomark::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 0.75rem;
height: 0.75rem;
background: #9b59b6;
border-radius: 50%;
}
/* :default pseudo-class */
.default-demo input:default {
border-color: #f39c12;
background-color: rgba(243, 156, 18, 0.1);
}
/* :indeterminate for checkboxes */
.indeterminate-checkbox input:indeterminate ~ .checkmark {
background: #95a5a6;
border-color: #95a5a6;
}
.indeterminate-checkbox input:indeterminate ~ .checkmark::after {
content: "โ";
position: absolute;
color: white;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
/* :placeholder-shown */
.placeholder-demo {
position: relative;
}
.placeholder-demo input {
width: 100%;
padding: 1rem;
border: 2px solid #bdc3c7;
border-radius: 8px;
font-size: 1rem;
}
.placeholder-demo input:placeholder-shown {
border-color: #e67e22;
}
.placeholder-demo input:not(:placeholder-shown) {
border-color: #27ae60;
}
/* :user-valid and :user-invalid */
.user-validation input {
width: 100%;
padding: 1rem;
border: 2px solid #bdc3c7;
border-radius: 8px;
font-size: 1rem;
transition: all 0.3s ease;
}
.user-validation input:user-valid {
border-color: #27ae60;
background-color: rgba(39, 174, 96, 0.05);
}
.user-validation input:user-invalid {
border-color: #c0392b;
background-color: rgba(192, 57, 43, 0.05);
}
.demo-section {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 10px;
margin: 1rem 0;
}
.code-example {
background: #2c3e50;
color: white;
padding: 1rem;
border-radius: 10px;
margin-top: 1rem;
font-family: monospace;
font-size: 0.8rem;
}
.browser-note {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 1rem;
margin: 1rem 0;
border-radius: 5px;
}
@media (max-width: 768px) {
.checkbox-group, .radio-group {
flex-direction: column;
}
.header h1 {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>โก Advanced Form Pseudo-classes</h1>
<p>Advanced state management for complex forms</p>
</div>
<div class="form-container">
<form id="advancedForm">
<!-- :in-range and :out-of-range -->
<div class="form-group">
<label for="age">Age (10-100):</label>
<input type="number" id="age" class="range-input" min="10" max="100" value="25">
<div class="code-example">
input:in-range { border-color: #2ecc71; }
input:out-of-range { border-color: #e74c3c; }
</div>
</div>
<!-- :checked for checkboxes -->
<div class="form-group">
<label>Interests:</label>
<div class="checkbox-group">
<label class="custom-checkbox">
<input type="checkbox" name="interests" value="tech" checked>
<span class="checkmark"></span>
Technology
</label>
<label class="custom-checkbox">
<input type="checkbox" name="interests" value="sports">
<span class="checkmark"></span>
Sports
</label>
<label class="custom-checkbox">
<input type="checkbox" name="interests" value="music">
<span class="checkmark"></span>
Music
</label>
</div>
<div class="code-example">
input:checked ~ .checkmark {
background: #3498db;
border-color: #3498db;
}
</div>
</div>
<!-- :checked for radio buttons -->
<div class="form-group">
<label>Preferred Contact:</label>
<div class="radio-group">
<label class="custom-radio">
<input type="radio" name="contact" value="email" checked>
<span class="radiomark"></span>
Email
</label>
<label class="custom-radio">
<input type="radio" name="contact" value="phone">
<span class="radiomark"></span>
Phone
</label>
<label class="custom-radio">
<input type="radio" name="contact" value="sms">
<span class="radiomark"></span>
SMS
</label>
</div>
<div class="code-example">
input:checked ~ .radiomark {
border-color: #9b59b6;
}
</div>
</div>
<!-- :default -->
<div class="form-group default-demo">
<label for="country">Country:</label>
<select id="country" class="form-control">
<option value="us" selected>United States</option>
<option value="ca">Canada</option>
<option value="uk">United Kingdom</option>
<option value="au">Australia</option>
</select>
<div class="code-example">
select:default {
border-color: #f39c12;
background-color: rgba(243, 156, 18, 0.1);
}
</div>
</div>
<!-- :indeterminate -->
<div class="form-group">
<label class="custom-checkbox indeterminate-checkbox">
<input type="checkbox" id="indeterminateCheckbox">
<span class="checkmark"></span>
Indeterminate State (Toggle with button below)
</label>
<button type="button" onclick="toggleIndeterminate()" style="margin-top: 0.5rem; padding: 0.5rem 1rem; background: #95a5a6; color: white; border: none; border-radius: 4px; cursor: pointer;">
Toggle Indeterminate
</button>
<div class="code-example">
input:indeterminate ~ .checkmark {
background: #95a5a6;
border-color: #95a5a6;
}
</div>
</div>
<!-- :placeholder-shown -->
<div class="form-group placeholder-demo">
<label for="search">Search:</label>
<input type="text" id="search" placeholder="Enter search terms...">
<div class="code-example">
input:placeholder-shown { border-color: #e67e22; }
input:not(:placeholder-shown) { border-color: #27ae60; }
</div>
</div>
<!-- :user-valid and :user-invalid -->
<div class="form-group user-validation">
<label for="username">Username (min 3 chars):</label>
<input type="text" id="username" required minlength="3" placeholder="Enter username">
<div class="browser-note">
<strong>Note:</strong> :user-valid and :user-invalid have limited browser support.
They only apply after user interaction.
</div>
<div class="code-example">
input:user-valid { border-color: #27ae60; }
input:user-invalid { border-color: #c0392b; }
</div>
</div>
</form>
</div>
</div>
<script>
function toggleIndeterminate() {
const checkbox = document.getElementById('indeterminateCheckbox');
checkbox.indeterminate = !checkbox.indeterminate;
}
// Demo for :user-valid and :user-invalid
document.getElementById('advancedForm').addEventListener('input', function(e) {
// Force validation display
e.target.reportValidity();
});
</script>
</body>
</html>Validation & UI States
Enhanced User Experience
Use :focus-within for container styling, :user-valid/:user-invalid for user-triggered validation, and create sophisticated validation feedback systems.
Validation & UI States Implementation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Validation & UI Pseudo-classes</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 3rem;
color: #2c3e50;
}
.header h1 {
font-size: 3rem;
margin-bottom: 1rem;
}
.form-container {
background: white;
border-radius: 15px;
padding: 2rem;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
/* Validation states with custom messages */
.validation-group {
position: relative;
margin-bottom: 2rem;
}
.validation-input {
width: 100%;
padding: 1rem;
border: 2px solid #bdc3c7;
border-radius: 8px;
font-size: 1rem;
transition: all 0.3s ease;
}
.validation-input:valid {
border-color: #27ae60;
}
.validation-input:invalid:not(:focus):not(:placeholder-shown) {
border-color: #e74c3c;
}
.validation-message {
display: none;
font-size: 0.875rem;
margin-top: 0.5rem;
padding: 0.5rem;
border-radius: 4px;
}
.validation-input:invalid:not(:focus):not(:placeholder-shown) ~ .validation-message {
display: block;
background-color: #f8d7da;
color: #721c24;
border-left: 4px solid #e74c3c;
}
.validation-input:valid ~ .validation-message.valid {
display: block;
background-color: #d4edda;
color: #155724;
border-left: 4px solid #28a745;
}
/* :focus-within for form groups */
.focus-within-group {
position: relative;
padding: 1.5rem;
border: 2px solid transparent;
border-radius: 10px;
margin-bottom: 2rem;
transition: all 0.3s ease;
}
.focus-within-group:focus-within {
border-color: #3498db;
background-color: rgba(52, 152, 219, 0.05);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
/* :enabled and :disabled states */
.state-buttons {
display: flex;
gap: 1rem;
margin: 1rem 0;
}
.state-button {
padding: 1rem 2rem;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
}
.state-button:enabled {
background: #3498db;
color: white;
}
.state-button:enabled:hover {
background: #2980b9;
transform: translateY(-2px);
}
.state-button:disabled {
background: #bdc3c7;
color: #7f8c8d;
cursor: not-allowed;
opacity: 0.6;
}
/* :read-only and :read-write */
.read-write-group {
margin: 2rem 0;
}
.read-write-input {
width: 100%;
padding: 1rem;
border: 2px solid #bdc3c7;
border-radius: 8px;
font-size: 1rem;
transition: all 0.3s ease;
}
.read-write-input:read-write {
background-color: #d4edda;
border-color: #28a745;
}
.read-write-input:read-only {
background-color: #f8d7da;
border-color: #e74c3c;
color: #721c24;
}
/* Progress bar with :indeterminate */
.progress-group {
margin: 2rem 0;
}
.progress-bar {
width: 100%;
height: 20px;
background: #ecf0f1;
border-radius: 10px;
overflow: hidden;
position: relative;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #3498db, #2980b9);
width: 60%;
transition: width 0.3s ease;
}
.progress-bar:indeterminate .progress-fill {
animation: indeterminate 1.5s infinite linear;
width: 50%;
}
@keyframes indeterminate {
0% { transform: translateX(-100%); }
100% { transform: translateX(200%); }
}
/* Custom select styles with :checked */
.custom-select {
position: relative;
margin: 2rem 0;
}
.select-button {
width: 100%;
padding: 1rem;
border: 2px solid #bdc3c7;
border-radius: 8px;
background: white;
cursor: pointer;
text-align: left;
}
.select-options {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 2px solid #bdc3c7;
border-radius: 8px;
margin-top: 0.5rem;
z-index: 10;
}
.select-option {
padding: 1rem;
cursor: pointer;
transition: background 0.3s ease;
}
.select-option:hover {
background: #3498db;
color: white;
}
.select-option:checked {
background: #2980b9;
color: white;
}
.custom-select:focus-within .select-options {
display: block;
}
.demo-section {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 10px;
margin: 1rem 0;
}
.code-example {
background: #2c3e50;
color: white;
padding: 1rem;
border-radius: 10px;
margin-top: 1rem;
font-family: monospace;
font-size: 0.8rem;
}
@media (max-width: 768px) {
.state-buttons {
flex-direction: column;
}
.header h1 {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>โ
Validation & UI States</h1>
<p>Advanced validation and user interface states</p>
</div>
<div class="form-container">
<form id="validationForm">
<!-- Validation with custom messages -->
<div class="validation-group">
<label for="email">Email Address:</label>
<input type="email" id="email" class="validation-input" placeholder="Enter valid email" required>
<div class="validation-message">
Please enter a valid email address
</div>
<div class="validation-message valid">
Email address looks good!
</div>
<div class="code-example">
input:invalid:not(:focus):not(:placeholder-shown) ~ .validation-message {
display: block;
background-color: #f8d7da;
}
</div>
</div>
<!-- :focus-within demo -->
<div class="focus-within-group">
<label for="name">Full Name:</label>
<input type="text" id="name" class="validation-input" placeholder="Enter your name" required>
<div class="code-example">
.form-group:focus-within {
border-color: #3498db;
background-color: rgba(52, 152, 219, 0.05);
}
</div>
</div>
<!-- :enabled and :disabled -->
<div class="demo-section">
<label>Button States:</label>
<div class="state-buttons">
<button type="button" class="state-button">Enabled Button</button>
<button type="button" class="state-button" disabled>Disabled Button</button>
</div>
<div class="code-example">
button:enabled { background: #3498db; color: white; }
button:disabled { background: #bdc3c7; cursor: not-allowed; }
</div>
</div>
<!-- :read-only and :read-write -->
<div class="read-write-group">
<label for="readWrite">Read-Write Field:</label>
<input type="text" id="readWrite" class="read-write-input" value="You can edit this field">
<label for="readOnly" style="margin-top: 1rem;">Read-Only Field:</label>
<input type="text" id="readOnly" class="read-write-input" value="This field is read-only" readonly>
<div class="code-example">
input:read-write { background-color: #d4edda; }
input:read-only { background-color: #f8d7da; }
</div>
</div>
<!-- Progress bar -->
<div class="progress-group">
<label>Progress Bar:</label>
<div class="progress-bar">
<div class="progress-fill"></div>
</div>
<button type="button" onclick="toggleProgress()" style="margin-top: 0.5rem; padding: 0.5rem 1rem; background: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer;">
Toggle Indeterminate
</button>
<div class="code-example">
.progress-bar:indeterminate .progress-fill {
animation: indeterminate 1.5s infinite linear;
}
</div>
</div>
</form>
</div>
</div>
<script>
let progressIndeterminate = false;
function toggleProgress() {
const progressBar = document.querySelector('.progress-bar');
progressIndeterminate = !progressIndeterminate;
if (progressIndeterminate) {
progressBar.setAttribute('indeterminate', '');
} else {
progressBar.removeAttribute('indeterminate');
}
}
// Real-time validation
document.getElementById('validationForm').addEventListener('input', function(e) {
const input = e.target;
input.reportValidity();
});
</script>
</body>
</html>Practical Examples
๐ Registration Forms
Real-time validation and user feedback
๐ Survey Forms
Interactive options with visual states
๐ Search & Filters
Dynamic filtering with CSS-only interactions
Practical Examples Implementation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Practical Form Examples</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 3rem;
color: #2c3e50;
}
.header h1 {
font-size: 3rem;
margin-bottom: 1rem;
}
.examples-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 2rem;
margin-bottom: 3rem;
}
.example-card {
background: white;
border-radius: 15px;
padding: 2rem;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
/* Registration Form */
.registration-form .form-group {
margin-bottom: 1.5rem;
}
.registration-form label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: #2c3e50;
}
.registration-form input {
width: 100%;
padding: 1rem;
border: 2px solid #bdc3c7;
border-radius: 8px;
font-size: 1rem;
transition: all 0.3s ease;
}
.registration-form input:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
.registration-form input:valid {
border-color: #2ecc71;
}
.registration-form input:invalid:not(:focus) {
border-color: #e74c3c;
}
.submit-btn {
width: 100%;
padding: 1rem;
background: #3498db;
color: white;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
}
.submit-btn:hover:enabled {
background: #2980b9;
transform: translateY(-2px);
}
.submit-btn:disabled {
background: #bdc3c7;
cursor: not-allowed;
opacity: 0.6;
}
/* Survey Form */
.survey-form .question {
margin-bottom: 2rem;
}
.options-group {
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: 1rem;
}
.option-label {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
border: 2px solid #ecf0f1;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
}
.option-label:hover {
border-color: #3498db;
background: rgba(52, 152, 219, 0.05);
}
.option-label:has(input:checked) {
border-color: #2ecc71;
background: rgba(46, 204, 113, 0.1);
}
/* Search Filter */
.search-filter {
margin: 2rem 0;
}
.filter-options {
display: flex;
gap: 1rem;
flex-wrap: wrap;
margin: 1rem 0;
}
.filter-btn {
padding: 0.5rem 1rem;
border: 2px solid #bdc3c7;
background: white;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s ease;
}
.filter-btn:checked {
background: #3498db;
color: white;
border-color: #3498db;
}
.filter-btn:hover {
border-color: #3498db;
}
/* Password Strength Meter */
.password-strength {
margin: 2rem 0;
}
.strength-meter {
height: 5px;
background: #ecf0f1;
border-radius: 5px;
margin: 0.5rem 0;
overflow: hidden;
}
.strength-fill {
height: 100%;
width: 0%;
transition: width 0.3s ease;
}
.password-input:valid ~ .strength-meter .strength-fill {
width: 100%;
background: #2ecc71;
}
.password-input:invalid:not(:focus):not(:placeholder-shown) ~ .strength-meter .strength-fill {
width: 33%;
background: #e74c3c;
}
.password-input:placeholder-shown ~ .strength-meter .strength-fill {
width: 0%;
}
/* Multi-step Form */
.multi-step-form {
position: relative;
}
.form-step {
display: none;
}
.form-step:first-child {
display: block;
}
.step-indicator {
display: flex;
justify-content: space-between;
margin-bottom: 2rem;
}
.step {
width: 30px;
height: 30px;
border-radius: 50%;
background: #bdc3c7;
display: flex;
align-items: center;
justify-content: center;
color: white;
}
.step.active {
background: #3498db;
}
.step.completed {
background: #2ecc71;
}
.nav-buttons {
display: flex;
gap: 1rem;
margin-top: 2rem;
}
.code-example {
background: #2c3e50;
color: white;
padding: 1rem;
border-radius: 10px;
margin-top: 1rem;
font-family: monospace;
font-size: 0.8rem;
}
@media (max-width: 768px) {
.examples-grid {
grid-template-columns: 1fr;
}
.header h1 {
font-size: 2rem;
}
.filter-options {
flex-direction: column;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>๐ Practical Form Examples</h1>
<p>Real-world form implementations using pseudo-classes</p>
</div>
<div class="examples-grid">
<!-- Registration Form -->
<div class="example-card">
<h3>๐ Registration Form</h3>
<form class="registration-form">
<div class="form-group">
<label for="regEmail">Email:</label>
<input type="email" id="regEmail" required placeholder="Enter your email">
</div>
<div class="form-group">
<label for="regPassword">Password:</label>
<input type="password" id="regPassword" required minlength="6" placeholder="Enter password">
</div>
<div class="form-group">
<label for="regConfirm">Confirm Password:</label>
<input type="password" id="regConfirm" required placeholder="Confirm password">
</div>
<button type="submit" class="submit-btn">Register</button>
</form>
<div class="code-example">
input:valid { border-color: #2ecc71; }
input:invalid:not(:focus) { border-color: #e74c3c; }
button:disabled { opacity: 0.6; cursor: not-allowed; }
</div>
</div>
<!-- Survey Form -->
<div class="example-card">
<h3>๐ Survey Form</h3>
<form class="survey-form">
<div class="question">
<label>How satisfied are you with our service?</label>
<div class="options-group">
<label class="option-label">
<input type="radio" name="satisfaction" value="very-satisfied" required>
<span>Very Satisfied</span>
</label>
<label class="option-label">
<input type="radio" name="satisfaction" value="satisfied">
<span>Satisfied</span>
</label>
<label class="option-label">
<input type="radio" name="satisfaction" value="neutral">
<span>Neutral</span>
</label>
<label class="option-label">
<input type="radio" name="satisfaction" value="unsatisfied">
<span>Unsatisfied</span>
</label>
</div>
</div>
</form>
<div class="code-example">
.option-label:has(input:checked) {
border-color: #2ecc71;
background: rgba(46, 204, 113, 0.1);
}
</div>
</div>
<!-- Search Filter -->
<div class="example-card">
<h3>๐ Search Filter</h3>
<div class="search-filter">
<input type="text" placeholder="Search products..." style="width: 100%; padding: 1rem; border: 2px solid #bdc3c7; border-radius: 8px; margin-bottom: 1rem;">
<div class="filter-options">
<label class="filter-btn">
<input type="checkbox" name="category" value="electronics" hidden>
Electronics
</label>
<label class="filter-btn">
<input type="checkbox" name="category" value="clothing" hidden>
Clothing
</label>
<label class="filter-btn">
<input type="checkbox" name="category" value="books" hidden>
Books
</label>
<label class="filter-btn">
<input type="checkbox" name="category" value="home" hidden>
Home
</label>
</div>
</div>
<div class="code-example">
.filter-btn:has(input:checked) {
background: #3498db;
color: white;
border-color: #3498db;
}
</div>
</div>
<!-- Password Strength -->
<div class="example-card">
<h3>๐ Password Strength Meter</h3>
<div class="password-strength">
<input type="password" class="password-input" placeholder="Enter password" required minlength="6" style="width: 100%; padding: 1rem; border: 2px solid #bdc3c7; border-radius: 8px;">
<div class="strength-meter">
<div class="strength-fill"></div>
</div>
<div style="font-size: 0.875rem; color: #7f8c8d; margin-top: 0.5rem;">
Password must be at least 6 characters long
</div>
</div>
<div class="code-example">
.password-input:valid ~ .strength-meter .strength-fill {
width: 100%;
background: #2ecc71;
}
</div>
</div>
</div>
<!-- Multi-step Form -->
<div class="example-card">
<h3>๐ข Multi-step Form</h3>
<form class="multi-step-form">
<div class="step-indicator">
<div class="step active">1</div>
<div class="step">2</div>
<div class="step">3</div>
</div>
<div class="form-step">
<h4>Personal Information</h4>
<div class="form-group">
<label for="firstName">First Name:</label>
<input type="text" id="firstName" required>
</div>
<div class="form-group">
<label for="lastName">Last Name:</label>
<input type="text" id="lastName" required>
</div>
</div>
<div class="nav-buttons">
<button type="button" class="submit-btn" style="background: #95a5a6;">Previous</button>
<button type="button" class="submit-btn">Next</button>
</div>
</form>
<div class="code-example">
.step.active { background: #3498db; }
.step.completed { background: #2ecc71; }
</div>
</div>
</div>
</body>
</html>Best Practices & Accessibility
โ Do's
- Use high contrast colors for validation states
- Provide clear visual feedback for all interactions
- Test with keyboard navigation
- Use :focus styles for accessibility
- Combine with ARIA attributes when needed
- Test across different devices and browsers
โ Don'ts
- Don't rely solely on color for validation
- Avoid removing default focus outlines completely
- Don't make forms too complex with excessive states
- Avoid using pseudo-classes for critical functionality
- Don't ignore browser support limitations
- Avoid overwhelming users with too much feedback
๐ฏ Browser Support Guide
Well Supported:
- :focus, :hover, :active
- :checked, :disabled
- :valid, :invalid
- :required, :optional
- :first-child, :last-child
Limited Support:
- :user-valid, :user-invalid
- :placeholder-shown (older browsers)
- :focus-visible (newer feature)
- :blank (experimental)
Ready to Build Better Forms? ๐
Experiment with form pseudo-classes and create interactive, accessible forms that provide immediate feedback to users. From simple validation to complex multi-step forms, these techniques will elevate your form design.