समस्या
जब कोई उपयोगकर्ता किसी फ़ील्ड पर फ़ोकस करता है और टाइप करना शुरू करता है, तो पुष्टि करने से जुड़ी गड़बड़ियां दिखाना जल्दबाज़ी है और इससे उपयोगकर्ता का ध्यान भटकता है. उदाहरण के लिए, जब कोई उपयोगकर्ता ईमेल पता (जैसे, "user@gm") या मुश्किल शर्तों वाला पासवर्ड टाइप करता है, तो फ़ील्ड को तब तक अमान्य माना जाता है, जब तक कि वह पूरा न हो जाए. स्टैंडर्ड :invalid स्टाइलिंग की वजह से, गड़बड़ी वाली स्थिति तुरंत दिखती है. इससे उपयोगकर्ता को परेशानी होती है.
समस्या का हल
:user-invalid स्यूडो-क्लास की मदद से, गड़बड़ी की स्थिति को तब तक के लिए टाला जा सकता है, जब तक उपयोगकर्ता किसी वैल्यू को "कमिट" नहीं कर देता (फ़ील्ड को धुंधला करके) या फ़ॉर्म सबमिट करने की कोशिश नहीं करता. इससे यह पक्का होता है कि पुष्टि करने से जुड़ा फ़ीडबैक, उपयोगकर्ता के फ़ील्ड से इंटरैक्ट करने के बाद ही दिया जाए.
लागू करने की रणनीति
- एचटीएमएल की पाबंदी: ब्राउज़र के पहले से मौजूद पुष्टि करने वाले लॉजिक को ट्रिगर करने के लिए,
type="email",pattern, औरrequiredजैसे स्टैंडर्ड HTML5 एट्रिब्यूट का इस्तेमाल करें. - विज़ुअल फ़ीडबैक: इंटरैक्शन के बाद ही गड़बड़ी की स्टाइलिंग लागू करने के लिए,
:user-invalidका इस्तेमाल करें. - पॉज़िटिव रीइन्फ़ोर्समेंट: ज़रूरी शर्तें पूरी होने पर, हरे रंग का "सफलता" इंडिकेटर दिखाने के लिए,
:user-validका इस्तेमाल करें. हालांकि, ऐसा करना ज़रूरी नहीं है. - गड़बड़ी को ठीक करना: जैसे ही उपयोगकर्ता इनपुट को मान्य फ़ॉर्मैट में सही करता है,
:user-invalidमैच करना बंद कर देता है. इससे गड़बड़ी की स्थिति तुरंत हट जाती है.
लागू करने के बारे में जानकारी
इस्तेमाल का पहला उदाहरण: ईमेल पते की पुष्टि करना
ज़रूरी: ईमेल फ़ील्ड के लिए, स्टैंडर्ड HTML5 एट्रिब्यूट का इस्तेमाल करें. गड़बड़ी का मैसेज डिफ़ॉल्ट रूप से छिपा होता है. यह सिर्फ़ तब दिखता है, जब ब्राउज़र को पता चलता है कि उपयोगकर्ता ने फ़ील्ड को अमान्य स्थिति में छोड़ दिया है.
<form>
<div class="field">
<label for="email">Email Address</label>
<!-- MANDATORY: Place format hints above the input so autocomplete popovers don't cover them during editing -->
<span id="email-hint" class="hint">Format: you@example.com</span>
<!-- DO: Use standard HTML validation attributes like type="email" and required -->
<input
type="email"
id="email"
name="email"
required
autocomplete="email"
aria-describedby="email-hint"
aria-errormessage="email-error"
>
<div id="email-error" class="error-msg">
<span aria-hidden="true">❌</span> Please enter a valid email address.
</div>
</div>
</form>
.hint {
display: block;
color: #5f6368;
font-size: 0.85rem;
margin-bottom: 0.25rem;
}
.error-msg {
display: none;
color: #d93025;
font-size: 0.875rem;
margin-top: 0.25rem;
}
/*
DO: Only show error styles after user interaction.
Use multiple indicators (border/background shift + icon/text) to avoid color-only states.
*/
input:user-invalid {
border-color: #d93025;
background-color: #fce8e6;
}
/* DO: Reveal the error message using the adjacent sibling selector */
input:user-invalid + .error-msg {
display: block;
}
/* DO: Provide a clear success indication on :user-valid */
input:user-valid {
border-color: #188038;
}
इस्तेमाल का दूसरा उदाहरण: पासवर्ड की जटिलता
ज़रूरी: pattern एट्रिब्यूट में Regex Lookahead पैटर्न का इस्तेमाल करके, पासवर्ड की जटिलता का नियम तय करें. उपयोगकर्ता को गाइड करने के लिए, नियमों की सूची इनपुट के ऊपर दिखाई जाती है. साथ ही, अगर कोई गड़बड़ी होती है, तो उसे हाइलाइट किया जाता है.
<form>
<div class="field">
<label for="password">New Password</label>
<!-- MANDATORY: Place hints and rules above the input so mobile keyboards do not obscure them -->
<ul id="password-rules" class="rules-list">
<li>At least 8 characters</li>
<li>One uppercase letter</li>
<li>One number</li>
<li>One special character</li>
</ul>
<!-- DO: Use pattern and minlength for complex password validation
DO: Match all constraints with lookaheads via pattern attribute
-->
<input
type="password"
id="password"
autocomplete="new-password"
required
pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).{8,}"
minlength="8"
aria-describedby="password-rules"
>
</div>
</form>
/* DO: State the default styling as neutral */
.rules-list {
color: #5f6368;
margin-bottom: 0.5rem;
}
/* DO: Show invalid state (After interaction): Error */
input:user-invalid {
border-color: #d93025;
background-color: #fce8e6;
}
/* DO: Highlight rules list when error is shown using the modern :has() selector */
.field:has(input:user-invalid) .rules-list {
color: #d93025;
font-weight: 600;
}
/* DO: Add success indications for :user-valid state */
input:user-valid {
border-color: #188038;
}
/* DO: Hide rules once satisfied */
.field:has(input:user-valid) .rules-list {
display: none;
}
फ़ॉलबैक और ब्राउज़र से जुड़ी सहायता
:user-valid और :user-invalid के लिए फ़ॉलबैक और ब्राउज़र सहायता
फ़ॉलबैक के लिए सीएसएस
input:user-invalid,
input.user-invalid-fallback {
border-color: #d93025;
background-color: #fce8e6;
}
input:user-invalid + .error-msg,
input.user-invalid-fallback + .error-msg {
display: block;
}
JavaScript फ़ॉलबैक
फिर से इस्तेमाल की जा सकने वाली ऐसी यूटिलिटी का इस्तेमाल करें जो WeakMap का इस्तेमाल करके, इंटरैक्शन की स्थिति को ट्रैक करती है. इससे डीओएम को "डर्टी" क्लास या डेटा एट्रिब्यूट से प्रदूषित होने से बचाया जा सकता है.
const UserInvalidFallback = (() => {
const dirtyState = new WeakMap();
const updateState = (input) => {
const isValid = input.checkValidity();
// Update both visual and ARIA state
input.classList.toggle('user-invalid-fallback', !isValid);
input.classList.toggle('user-valid-fallback', isValid);
if (!isValid) {
input.setAttribute('aria-invalid', 'true');
} else {
input.removeAttribute('aria-invalid');
}
};
const handleEvent = (event) => {
const input = event.target;
if (event.type === 'reset') {
const controls = input.elements || [];
for (const control of controls) {
dirtyState.delete(control);
control.classList.remove('user-invalid-fallback');
control.classList.remove('user-valid-fallback');
control.removeAttribute('aria-invalid');
}
return;
}
if (!input.checkValidity) return;
if (event.type === 'input' || event.type === 'change') {
const state = dirtyState.get(input) || { hasInteracted: false, hasBlurred: false };
state.hasInteracted = true;
dirtyState.set(input, state);
if (state.hasBlurred) {
updateState(input);
}
} else if (event.type === 'blur') {
const state = dirtyState.get(input) || { hasInteracted: false, hasBlurred: false };
state.hasBlurred = true;
dirtyState.set(input, state);
if (state.hasInteracted) {
updateState(input);
}
}
};
const init = (root = document) => {
if (CSS.supports('selector(:user-invalid)')) return;
root.addEventListener('blur', handleEvent, true); // Capture phase
root.addEventListener('input', handleEvent);
root.addEventListener('change', handleEvent);
root.addEventListener('reset', handleEvent, true); // Capture resets
};
return { init };
})();
// Initialize for a specific form
const form = document.querySelector('#demo-form');
UserInvalidFallback.init(form);
ध्यान में रखने लायक अन्य बातें
- सुलभता:
- ज़रूरी: नियमों की सूची को इनपुट से लिंक करने के लिए,
aria-describedbyका इस्तेमाल करें. - ऐसा न करें: इनपुट के मान्य होने तक, नियमों की सूचियों को पूरी तरह से न छिपाएं. उपयोगकर्ताओं को यह पता होना चाहिए कि उन्हें क्या टाइप करना है!
- ज़रूरी: नियमों की सूची को इनपुट से लिंक करने के लिए,
- पैटर्न एट्रिब्यूट की सीमाएं: ज़रूरी:
patternएट्रिब्यूट, पूरी तरह से मैच करता है (इसमें^...$शामिल है). पक्का करें कि आपके पासवर्ड का रेगुलर एक्सप्रेशन, पूरी स्ट्रिंग के लिए हो. - पुष्टि करने की प्रोसेस कितनी सख्त है: ध्यान दें कि ब्राउज़र की डिफ़ॉल्ट
type="email"पुष्टि करने की प्रोसेस काफ़ी आसान है. उदाहरण के लिए,user@localserverपास हो सकता है. अगर आपको ज़्यादा सख्त पुष्टि की ज़रूरत है, तो आपकोtype="email"के साथ-साथ, ज़्यादा बेहतर पुष्टि करने वाली लाइब्रेरी या कस्टम पुष्टि करने वाले फ़ंक्शन का इस्तेमाल करना पड़ सकता है. - फ़ोकस मैनेजमेंट: ज़रूरी: अगर कोई उपयोगकर्ता अमान्य फ़ील्ड वाला फ़ॉर्म सबमिट करता है, तो ब्राउज़र अपने-आप पहले अमान्य फ़ील्ड पर फ़ोकस करेगा.
:user-invalidस्टाइल तुरंत लागू हो जाएंगी, क्योंकि सबमिट करने की कोशिश को इंटरैक्शन माना जाता है. - एक जैसा ARIA अनुभव: नेटिव
:user-invalid, ARIA एट्रिब्यूट के साथ अपने-आप सिंक नहीं होता.aria-invalidको विज़ुअल स्टेट के साथ सिंक करने के लिए, यह JavaScript जोड़ें:
// Sync aria-invalid with the CSS :user-invalid state
const syncAria = (el) => {
el.setAttribute?.('aria-invalid', el.matches(':user-invalid') ? 'true' : 'false');
};
// Update on blur (to show error) and input (to clear it)
document.addEventListener('blur', (e) => syncAria(e.target), true);
document.addEventListener('input', (e) => {
if (e.target.hasAttribute('aria-invalid')) syncAria(e.target);
});