CSS :user-valid Pseudo-Class
The CSS :user-valid pseudo-class selects form controls that satisfy their validation constraints after the browser determines that sufficient user interaction has occurred. Unlike :valid, which can match controls immediately when a page loads, :user-valid allows positive validation styling to appear after the user interacts with a field. It is useful for providing feedback without marking untouched form controls as successfully completed.
:user-valid Syntax
:user-valid {
property: value;
}
The pseudo-class matches a valid form control when the browser's user-interaction conditions are satisfied.
Basic Example
input:user-valid {
border: 2px solid #228b22;
}
Applies a green border when an input matches :user-valid.
Multiple Form Controls
input:user-valid,
select:user-valid,
textarea:user-valid {
border-color: #228b22;
}
Class Selector
.form-control:user-valid {
background-color: #effbef;
}
No Arguments
The pseudo-class is written as :user-valid, without parentheses or arguments.
How :user-valid Works
The browser evaluates HTML constraint validation rules to determine whether a form control is valid. The :user-valid pseudo-class adds an interaction condition so that valid-state styling is not necessarily displayed before the user has worked with the control.
Step 1 - Create a Required Input
<label for="username">Username</label>
<input type="text" id="username" name="username" minlength="4" required>
Step 2 - Add Valid-State Styling
input:user-valid {
border: 2px solid #228b22;
background-color: #effbef;
}
Step 3 - Enter a Valid Value
Enter a username that satisfies the required and minimum-length constraints. The browser may apply the :user-valid state after the relevant user interaction.
Step 4 - Change the Value
If the value becomes invalid, the control stops matching :user-valid. It may match :user-invalid when the browser's interaction conditions are satisfied.
No JavaScript Required
Native HTML validation and CSS can provide basic valid-state feedback without JavaScript.
HTML Form Validation
The :user-valid pseudo-class uses the browser's built-in constraint validation system.
Required Fields
<input type="text" name="name" required>
A required text field becomes valid when it contains a value that satisfies its constraints.
Email Addresses
<input type="email" name="email" required>
The entered value must satisfy the browser's email address validation rules.
Minimum Length
<input type="text" name="username" minlength="4" required>
The user-entered value must satisfy the applicable minimum-length constraint.
Number Ranges
<input type="number" name="quantity" min="1" max="10" required>
The entered number must fall within the permitted range and satisfy any other applicable constraints.
Pattern Matching
<input type="text" name="code" pattern="[A-Z]{3}" title="Enter three uppercase letters" required>
A valid value must match the specified pattern.
Constraint Validation
The selector does not create validation rules. It styles controls that satisfy existing constraints after the browser's interaction condition is met.
User Interaction
The :user-valid pseudo-class helps delay positive validation feedback until it is appropriate to show.
Before Interaction
An optional empty input may match :valid immediately, but it generally does not match :user-valid before relevant interaction.
After Editing
Entering a valid value can cause the control to match :user-valid once the browser's interaction conditions are satisfied.
After Leaving a Field
Moving focus away from a field can affect when the browser applies user-valid styling.
After Form Submission
An attempted form submission can affect user-interaction validity states. The control must still be valid to match :user-valid.
Browser-Determined Timing
Browsers determine when sufficient interaction has occurred. Do not assume that all browsers apply :user-valid immediately after the first keystroke or focus change.
:valid vs. :user-valid
Both pseudo-classes select valid form controls, but their matching conditions differ.
| 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 |
Using :valid
input:valid {
border-color: #228b22;
}
This may style an optional empty input as valid immediately.
Using :user-valid
input:user-valid {
border-color: #228b22;
}
This allows the browser to delay the positive styling until relevant user interaction occurs.
:user-valid vs. :user-invalid
These related pseudo-classes provide positive and negative validation feedback after user interaction.
| Pseudo-Class | Matches |
|---|---|
:user-valid | Valid controls when the user-interaction conditions are satisfied. |
:user-invalid | Invalid controls when the user-interaction conditions are satisfied. |
Combined Example
input:user-valid {
border-color: #228b22;
}
input:user-invalid {
border-color: #c62828;
}
Neutral Initial State
input {
border: 2px solid #999;
}
A neutral border provides a consistent initial appearance before validation feedback becomes appropriate.
Changing Between States
As a user edits a control, the browser can update which validation pseudo-class matches. A control cannot be both valid and invalid at the same time.
Validation Attributes
HTML attributes establish the validation requirements that a control must satisfy before it can match :user-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 text 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 every applicable constraint to be valid.
Disabled Controls
Disabled form controls generally do not participate in constraint validation and do not match :user-valid.
Form Submission
Valid form controls may receive positive styling after user interaction or an attempted submission, depending on browser behavior.
HTML Example
<form action="/submit" method="post">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<button type="submit">Submit</button>
</form>
CSS Example
input:user-valid {
border: 2px solid #228b22;
}
Successful Validation
When the entered email address satisfies the control's constraints and the interaction conditions are met, the field can match :user-valid.
Native Validation
The browser normally checks applicable constraints before allowing a form to submit.
The novalidate Attribute
The novalidate attribute disables interactive constraint validation during form submission. It does not remove the underlying validity states of individual controls.
Server-Side Validation
Client-side validation improves the user experience but does not replace server-side validation.
:user-valid Specificity
The :user-valid pseudo-class contributes a specificity of 0-1-0, like other standard pseudo-classes.
Specificity Examples
| Selector | Specificity |
|---|---|
:user-valid | 0-1-0 |
input:user-valid | 0-1-1 |
.form-control:user-valid | 0-2-0 |
#email:user-valid | 1-1-0 |
:where(input:user-valid) | 0-0-0 |
Specificity Example
input {
border: 2px solid #999;
}
input:user-valid {
border-color: #228b22;
}
The second rule has higher specificity and changes the border color when the control matches :user-valid, assuming other cascade factors are equal.
Accessibility
Positive validation feedback should be understandable without relying entirely on color or visual appearance.
Do Not Rely on Color Alone
A green border alone may not clearly communicate successful validation to every user.
Use Visible Labels
<label for="email-address">Email Address</label>
<input type="email" id="email-address" name="email" required>
Provide Clear 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>
Maintain Focus Indicators
Do not remove visible focus outlines when adding valid-state styling.
Screen Reader Feedback
The :user-valid pseudo-class changes styling but does not automatically announce a successful validation state to assistive technology.
Avoid Excessive Feedback
Use success indicators where they help users understand requirements rather than marking every optional field as successfully completed.
Best Practices
- Use
:user-validto delay positive validation feedback until meaningful user interaction. - Define appropriate constraints with HTML attributes such as
required,pattern, andminlength. - Keep untouched form controls visually neutral.
- Use
:user-invalidfor corresponding error styling when appropriate. - Do not rely on color alone to communicate validation results.
- Provide clear labels and instructions for required input formats.
- Preserve keyboard focus indicators.
- Test validation timing in multiple browsers.
- Use server-side validation for submitted data.
:user-valid Example
This example uses a required email field. Enter a valid email address and leave the field to see the positive validation styling when the browser applies :user-valid. Enter an invalid address or submit an incomplete form to see the corresponding invalid state.
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:user-valid {
border-color: #228b22;
background-color: #effbef;
}
#validation-demo input:user-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 a successful form submission from navigating away from the example. The browser handles the validation states.
Browser Result
Note: The field receives a green border and light green background when it matches :user-valid. Invalid styling appears when it matches :user-invalid. The timing depends on browser validation behavior.
Browser Support
Baseline: Newly available. The :user-valid pseudo-class is supported in current versions of major browsers, including Chrome, Edge, Firefox, and Safari. Older browser versions may not recognize the selector.
For current compatibility information, visit Can I Use? for :user-valid and :user-invalid support.
Specifications
The :user-valid pseudo-class is defined in CSS Selectors Level 4 as a user-interaction pseudo-class for form validation.
