সমস্যা
পৃষ্ঠা লোড হওয়ার সাথে সাথেই প্রয়োজনীয় ফিল্ডে সমস্যা সংক্রান্ত স্ট্যাটাস দেখানো হলে তা বিভ্রান্তিকর হতে পারে। সাধারণত, কোনও আবশ্যক ফিল্ড তখনই "ভুল" হিসেবে দেখানো উচিত যখন ব্যবহারকারী সেটি পূরণ করার চেষ্টা করেও ব্যর্থ হয়েছেন।
সমাধান
:user-invalid সিউডো-ক্লাস এই সমস্যার নিখুঁত সমাধান করে। প্রয়োজনীয় ফিল্ডের ক্ষেত্রে, পৃষ্ঠা লোড হওয়ার সময় এটি মিলবে না। এটি শুধুমাত্র তখনই মিলবে যদি:
- ব্যবহারকারী ফিল্ডের সাথে ইন্টার্যাক্ট করেন (যেমন, কোনও অক্ষর টাইপ করে মুছে দেন) এবং তারপর সেটি ছেড়ে দেন (ব্লার), ফিল্ডটি খালি রেখে দেন।
- ব্যবহারকারী ফিল্ডটি খালি রেখে ফর্ম জমা দেওয়ার চেষ্টা করেন।
প্রয়োগ সংক্রান্ত স্ট্র্যাটেজি
- HTML কনস্ট্রেন্ট: আপনার ইনপুটে
requiredঅ্যাট্রিবিউট যোগ করুন। - ভিজ্যুয়াল ফিডব্যাক: বর্ডার লাল রঙের করতে এবং "প্রয়োজনীয়" সহায়ক টেক্সট দেখাতে
:user-invalidব্যবহার করুন। - টাইমিং: ভিজ্যুয়াল ফিডব্যাকের জন্য ব্রাউজারের নেটিভ টাইমিংয়ের উপর নির্ভর করুন।
touchedক্লাস যোগ করার জন্য আপনার আরonBlurহ্যান্ডলারের প্রয়োজন নেই, যদিও ARIA অ্যাট্রিবিউট সিঙ্ক করার জন্য এখনও কিছু জাভাস্ক্রিপ্টের প্রয়োজন (নিচে দেখুন)।
প্রয়োগ করার নির্দেশিকা
১. HTML স্ট্রাকচার
<form id="feedback-form">
<div class="field">
<label for="full-name">Full Name</label>
<input
type="text"
id="full-name"
name="full-name"
required
aria-errormessage="name-error"
>
<!-- MANDATORY: Include an icon or distinct non-color indicator alongside error text -->
<div id="name-error" class="error-msg">
<span aria-hidden="true">❌</span> This field is required.
</div>
</div>
</form>
২. CSS
.error-msg {
display: none;
color: #d93025;
font-size: 0.875rem;
margin-top: 0.25rem;
}
/*
Only highlight empty required fields AFTER the user visits them.
MANDATORY: Provide multiple indicators (border shift + helper text/icon) to avoid color-only state communication.
*/
input:user-invalid {
border-color: #d93025;
background-color: #fce8e6;
}
input:user-invalid + .error-msg {
display: block;
}
/* Optional: Subtle indicator for required fields that are valid */
input:required:user-valid {
border-color: #188038;
border-width: 2px;
}
৩. জাভাস্ক্রিপ্ট স্টেট সিঙ্ক্রোনাইজেশন
বাধ্যতামূলক: যেহেতু :user-invalid একটি ভিজ্যুয়াল স্টেট, তাই ব্যবহারকারী কোনও ভুল ফিল্ড ব্লার করলে বা জমা দেওয়ার চেষ্টা করলে, আপনাকে অবশ্যই সহায়ক প্রযুক্তির জন্য ডাইনামিকভাবে aria-invalid="true" সিঙ্ক করতে একটি জাভাস্ক্রিপ্ট ব্রিজ প্রদান করতে হবে।
const form = document.getElementById('feedback-form');
const syncAriaInvalid = (input) => {
if (!input.checkValidity()) {
input.setAttribute('aria-invalid', 'true');
} else {
input.removeAttribute('aria-invalid');
}
};
// Sync on blur when a user finishes interacting
form.addEventListener('blur', (e) => {
if (e.target.matches('input[required]')) {
syncAriaInvalid(e.target);
}
}, true);
// Sync all required fields when submission is attempted
form.addEventListener('submit', () => {
form.querySelectorAll('input[required]').forEach(syncAriaInvalid);
});
// Remove error state immediately upon correction
form.addEventListener('input', (e) => {
if (e.target.matches('input[required]') && e.target.checkValidity()) {
e.target.removeAttribute('aria-invalid');
}
});
ফলব্যাকিং ও ব্রাউজার সাপোর্ট
:user-valid এবং :user-invalid-এর জন্য ফলব্যাক ও ব্রাউজার সাপোর্ট
ফলব্যাকের জন্য CSS
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;
}
জাভাস্ক্রিপ্ট ফলব্যাক
WeakMap ব্যবহার করে ইন্টার্যাকশন স্টেট ট্র্যাক করে এমন একটি পুনর্ব্যবহারযোগ্য ইউটিলিটি ব্যবহার করুন। এটি "খারাপ" ক্লাস বা ডেটা অ্যাট্রিবিউট দিয়ে DOM দূষিত হওয়া এড়ায়।
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);
বিবেচনা করার মতো অন্যান্য বিষয়
- অ্যাস্টেরিস্ক: লেবেলে প্রয়োজনীয় ফিল্ডগুলি ভিজ্যুয়ালি (যেমন, অ্যাস্টেরিস্ক
*দিয়ে) দেখানো এখনও পেশাদার পদ্ধতি হিসেবে বিবেচিত হয়, যাতে ব্যবহারকারীরা ইন্টার্যাক্ট করার আগে কী আশা করতে হবে তা জানতে পারেন। - জমা দেওয়ার বোতাম:
disabledবোতামের মতো নয়, আপনার জমা দেওয়ার বোতাম চালু রাখুন। ব্যবহারকারী এটিতে ক্লিক করলে, ব্রাউজার অটোমেটিক সব খালি প্রয়োজনীয় ফিল্ডে:user-invalidট্রিগার করবে এবং প্রথমটিতে ফোকাস করবে। এটি অ্যাক্সেসিবিলিটি ও UX-এর জন্য দারুণ। - অ্যাক্সেসিবিলিটি: নেটিভ
:user-invalidARIA অ্যাট্রিবিউটের সাথে অটোমেটিক সিঙ্ক হয় না। ভিজ্যুয়াল অবস্থার সাথেaria-invalidসিঙ্ক করে রাখতে নিম্নলিখিত জাভাস্ক্রিপ্ট যোগ করুন:
// 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);
});