মেনু ইন্টার‍্যাকশন বেছে নিন

ওয়েব ফিচার: :user-valid এবং :user-invalid

সমস্যা

বাধ্যতামূলক ড্রপডাউনের (যেমন, "দেশ বেছে নিন") ক্ষেত্রে, ডিফল্ট বিকল্পের ভ্যালু খালি থাকলে, স্ট্যান্ডার্ড যাচাইকরণ ফিল্ডটিকে অবিলম্বে অবৈধ হিসেবে ফ্ল্যাগ করে। এর ফলে ভিজ্যুয়াল নয়েজ তৈরি হতে পারে। ব্যবহারকারী মেনু খুলে কোনও বিকল্প বেছে না নিয়ে বন্ধ করে দিলে অথবা ফর্ম জমা দেওয়ার চেষ্টা করলে তবেই আমরা সমস্যাটি দেখাতে চাই।

সমাধান

:user-invalid সিউডো-ক্লাস <select> এলিমেন্টের সাথে নির্বিঘ্নে কাজ করে। এটি ব্যবহারকারীর ইন্টার‍্যাকশন ফ্লোকে সম্মান করে: কোনও পরিবর্তন না করে শুধু পৃষ্ঠা লোড করা বা ফোকাস/ব্লার করাকে ইন্টার‍্যাকশন হিসেবে গণ্য করা হয় না, তাই ব্যবহারকারী সক্রিয়ভাবে কোনও বিকল্প বেছে নেওয়ার চেষ্টা না করা পর্যন্ত ফিল্ডটি নিরপেক্ষ থাকে।

প্রয়োগ সংক্রান্ত স্ট্র্যাটেজি

  1. HTML সীমাবদ্ধতা: required-এর সাথে <select> ব্যবহার করুন। প্রথম বিকল্পে value="" থাকতে হবে এবং সঠিক বিকল্প বেছে নেওয়ার জন্য বাধ্য করতে আদর্শগতভাবে বন্ধ/লুকিয়ে রাখতে হবে।
  2. ভিজ্যুয়াল ফিডব্যাক: বেছে নেওয়া বক্সের বর্ডার স্টাইল করতে :user-invalid ব্যবহার করুন।
  3. টাইমিং: ব্যবহারকারী কন্ট্রোল ব্লার করার আগে বা ফর্ম জমা দেওয়ার সময় ভ্যালু পরিবর্তন করলে (এমনকি ডিফল্ট অবৈধ অবস্থায় ফিরিয়ে আনলেও), ব্রাউজার ফিল্ডটিকে "ইন্টার‍্যাক্ট করা হয়েছে" হিসেবে বিবেচনা করে।

প্রয়োগ করার নির্দেশিকা

১. HTML স্ট্রাকচার

"placeholder" বিকল্পটি এখানে গুরুত্বপূর্ণ।

<form>
  <div class="field">
    <label for="country">Country</label>
    <select
      id="country"
      name="country"
      required
      aria-errormessage="country-error"
    >
      <option value="" disabled selected>Select a country...</option>
      <option value="us">United States</option>
      <option value="ca">Canada</option>
      <option value="uk">United Kingdom</option>
    </select>
    <div id="country-error" class="error-msg">
      Please select a country.
    </div>
  </div>
</form>

২. CSS

.error-msg {
  display: none;
  color: #d93025;
  font-size: 0.875rem;
  margin-top: 0.25rem;
}

/*
  Only show error after the user visits the select menu.
*/
select:user-invalid {
  border-color: #d93025;
  background-color: #fce8e6;
}

select:user-invalid + .error-msg {
  display: block;
}

select:user-valid {
  border-color: #188038;
}

ফলব্যাকিং ও ব্রাউজার সাপোর্ট

: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);

বিবেচনা করার মতো অন্যান্য বিষয়

  1. মোবাইলে আচরণ: মোবাইল ডিভাইসে, OS পিকারের উপর নির্ভর করে "ব্লার" আলাদাভাবে হতে পারে। আসল ডিভাইসে পরীক্ষা করার সাজেশন দেওয়া হয়।
  2. অ্যাক্সেসিবিলিটি: নেটিভ :user-invalid ARIA অ্যাট্রিবিউটের সাথে অটোমেটিক সিঙ্ক হয় না। ভিজ্যুয়াল অবস্থার সাথে 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);
});