CSS :valid Pseudo-Class
The CSS :valid pseudo-class selects form controls whose values satisfy their HTML validation constraints. It can style inputs, selects, and other form elements that pass validation, providing visual feedback as users complete a form. Unlike :user-valid, the :valid pseudo-class does not require prior user interaction and can match a control as soon as the page loads.
:valid Syntax
:valid {
property: value;
}
The :valid pseudo-class matches a form control when its value satisfies all applicable validation constraints.
Basic Example
input:valid {
border: 2px solid #228b22;
}
Applies a green border to inputs that pass validation.
Multiple Form Controls
input:valid,
select:valid,
textarea:valid {
border-color: #228b22;
}
Required Valid Inputs
input:required:valid {
border-color: #228b22;
}
Limits the styling to required inputs that currently pass validation.
Class Selector
.form-control:valid {
background-color: #effbef;
}
No Arguments
The pseudo-class is written as :valid, without parentheses or arguments.
How :valid Works
The browser evaluates HTML constraint validation rules. When a control satisfies all applicable constraints, it matches :valid. If it fails a constraint, it may match :invalid instead.
Step 1 - Create a Required Input
<label for="username">Username</label>
<input type="text" id="username" name="username" minlength="4" required>
Step 2 - Add Validation Styling
input:valid {
border-color: #228b22;
}
input:invalid {
border-color: #c62828;
}
Step 3 - Enter a Valid Value
Enter a username that satisfies the required and minimum-length constraints. The input matches :valid when all applicable constraints are satisfied.
Step 4 - Enter an Invalid Value
Remove the required value or enter a user-provided value that violates an applicable constraint. The input stops matching :valid and matches :invalid.
Automatic Updates
The browser updates validation pseudo-class matching as the control's validity changes. No JavaScript is required for basic styling.
HTML Constraint Validation
HTML constraint validation determines whether form controls satisfy requirements such as required values, permitted ranges, and input formats.
Text Inputs
<input type="text" name="username" minlength="4" required>
The control is valid when all applicable constraints are satisfied.
Email Inputs
<input type="email" name="email" required>
The entered value must satisfy the browser's email validation rules.
Number Inputs
<input type="number" name="quantity" min="1" max="10" required>
The entered number must satisfy the permitted range and any applicable step constraint.
Select Elements
<select name="size" required>
<option value="">Choose a size</option>
<option value="small">Small</option>
<option value="large">Large</option>
</select>
The required select becomes valid when an acceptable option is selected.
Textarea Elements
<textarea name="message" required></textarea>
A required textarea must contain a value to satisfy its required constraint.
Custom Validity
JavaScript can establish custom validation errors using setCustomValidity(). A control with a nonempty custom validation message is invalid until that message is cleared.
Validation Attributes
HTML validation attributes define the requirements that a control must satisfy to match :valid.
| Attribute or Type | Validation Purpose |
|---|---|
required | Requires a value or selection. |
minlength | Sets a minimum text length. |
maxlength | Sets a maximum text length. |
pattern | Requires a text value to match a regular expression. |
min | Sets a minimum permitted value. |
max | Sets a maximum permitted value. |
step | Restricts permitted numeric or date increments. |
type="email" | Checks email address syntax. |
type="url" | Checks URL syntax. |
Multiple Constraints
<label for="account-name">Account Name</label>
<input type="text" id="account-name" name="account-name" minlength="4" maxlength="20" required>
The control must satisfy all applicable constraints to match :valid.
Constraint Applicability
Not every validation attribute applies to every input type. For example, min and max are useful for numeric and certain date-related controls, while pattern applies to supported text-based input types.
:valid vs. :invalid
The :valid and :invalid pseudo-classes represent opposite constraint validation states.
| Feature | :valid | :invalid |
|---|---|---|
| Matches controls that pass validation | Yes | No |
| Matches controls that fail validation | No | Yes |
| Requires user interaction | No | No |
| Can match on page load | Yes | Yes |
Combined Example
input:valid {
border-color: #228b22;
}
input:invalid {
border-color: #c62828;
}
Initial Validation States
An empty required input can match :invalid immediately, while an empty optional input can match :valid immediately.
Mutually Exclusive States
A control participating in constraint validation cannot match both :valid and :invalid at the same time.
:valid vs. :user-valid
The :valid pseudo-class responds to the current validity of a control, while :user-valid also considers user interaction.
| Feature | :valid | :user-valid |
|---|---|---|
| Matches valid controls | Yes | Yes |
| Requires user-interaction conditions | No | Yes |
| Can match an untouched optional field | Yes | Generally no |
| Useful for delayed success styling | Less suitable by itself | Yes |
Immediate Valid Styling
input:valid {
border-color: #228b22;
}
Interaction-Based Valid Styling
input:user-valid {
border-color: #228b22;
}
Use :user-valid when success styling should generally wait until the user has interacted with a field.
Optional and Required Fields
Whether a field is required affects its initial validity state.
Optional Text Input
<input type="text" name="nickname">
An empty optional text input is normally valid.
Required Text Input
<input type="text" name="username" required>
An empty required text input is invalid.
Required and Valid
input:required:valid {
border-color: #228b22;
}
This selector limits valid-state styling to required inputs.
Optional and Valid
input:optional:valid {
border-color: #228b22;
}
Optional inputs can match this selector even when they are empty, provided they satisfy all applicable constraints.
Filled Required Fields
Filling a required field does not automatically make it valid. Other constraints, such as email format or numeric range, must also be satisfied.
Form-Level Validation
The :valid pseudo-class can also match a form when all of its relevant form controls are valid.
HTML Example
<form id="signup-form">
<label for="signup-name">Name</label>
<input type="text" id="signup-name" name="name" required>
<label for="signup-email">Email</label>
<input type="email" id="signup-email" name="email" required>
<button type="submit">Submit</button>
</form>
CSS Example
form:valid {
border: 2px solid #228b22;
}
form:invalid {
border: 2px solid #c62828;
}
The form matches :valid when its associated controls satisfy their validation requirements. It matches :invalid when a relevant control fails validation.
Fieldset Validation
A fieldset can also match :valid or :invalid based on the validity of its descendant form controls.
Native Submission Validation
Browsers normally prevent form submission when a participating control fails constraint validation, unless interactive validation has been disabled.
Server-Side Validation
Client-side validation does not replace server-side validation. All submitted values must still be checked by the server.
:valid Specificity
The :valid pseudo-class contributes a specificity of 0-1-0, like other standard pseudo-classes.
Specificity Examples
| Selector | Specificity |
|---|---|
:valid | 0-1-0 |
input:valid | 0-1-1 |
.form-control:valid | 0-2-0 |
#email:valid | 1-1-0 |
:where(input:valid) | 0-0-0 |
Specificity Example
input {
border: 2px solid #999;
}
input:valid {
border-color: #228b22;
}
The second selector has higher specificity and changes the border color when the input is valid, assuming other cascade factors are equal.
Accessibility
Validation feedback should be understandable to users who rely on keyboards, screen readers, or alternative visual presentations.
Do Not Rely on Color Alone
A green border alone may not clearly communicate a valid state to every user. Provide descriptive feedback when it is important to confirm successful validation.
Visible Labels
<label for="email-address">Email Address</label>
<input type="email" id="email-address" name="email" required>
Helpful Instructions
<label for="access-code">Access Code</label>
<input type="text" id="access-code" name="access-code" pattern="[0-9]{4}" aria-describedby="code-help" required>
<p id="code-help">Enter a four-digit code.</p>
Focus Indicators
Do not remove visible keyboard focus indicators when applying validation styling.
Screen Reader Feedback
The :valid pseudo-class changes visual styling. It does not automatically announce that a field is valid or update custom ARIA attributes.
Avoid Premature Success Messages
Optional empty fields can match :valid. Use :user-valid or more specific selectors when you want to avoid suggesting that an untouched field has been completed.
Best Practices
- Use
:validto style controls that satisfy their HTML validation requirements. - Define appropriate constraints with attributes such as
required,pattern, andmin. - Remember that optional empty controls can match
:validimmediately. - Use
:user-validwhen success styling should wait for user interaction. - Combine
:validand:invalidwhen both validation states need styling. - Use descriptive labels and clear input instructions.
- Do not rely on color alone to communicate validation results.
- Preserve visible keyboard focus indicators.
- Test form behavior with both valid and invalid values.
- Always validate submitted data on the server.
:valid Example
This example demonstrates how :valid and :invalid respond to a required email field. The input starts in an invalid state because it is empty. Enter a properly formatted email address to make the input valid.
HTML
<form id="validation-demo">
<label for="demo-email">Email Address</label>
<input type="email" id="demo-email" name="email" placeholder="name@example.com" required>
<button type="submit">Check Email</button>
<p id="form-status" role="status"></p>
</form>
CSS
#validation-demo label {
display: block;
margin-bottom: 6px;
}
#validation-demo input {
display: block;
width: 100%;
max-width: 260px;
box-sizing: border-box;
padding: 8px;
border: 2px solid #999;
border-radius: 4px;
}
#validation-demo input:valid {
border-color: #228b22;
background-color: #effbef;
}
#validation-demo input:invalid {
border-color: #c62828;
background-color: #fff0f0;
}
#validation-demo button {
margin-top: 12px;
padding: 8px 12px;
cursor: pointer;
}
JavaScript
document.getElementById("validation-demo").addEventListener("submit", (event) => {
event.preventDefault();
document.getElementById("form-status").textContent = "Email is valid.";
});
The JavaScript prevents successful submission from navigating away from the example. The browser handles the validation states automatically.
Browser Result
Note: The required email field starts with a red border because it is invalid. Enter a valid email address to display the green border and background. Unlike :user-valid, the :valid pseudo-class does not wait for user interaction.
Browser Support
Baseline: Widely available. The :valid pseudo-class is supported in all major modern browsers, including Chrome, Edge, Firefox, Safari, and Opera.
For current compatibility information, visit Can I Use? and search for :valid.
Specifications
The :valid pseudo-class is defined in CSS Selectors Level 4 as a validity pseudo-class for form controls and related elements.
