ইন্টার‍্যাকশনের পরে ইনপুট যাচাই করুন

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

সমস্যা

ব্যবহারকারী কোনও ফিল্ডে ফোকাস করে টাইপ করা শুরু করার সাথে সাথেই যাচাইকরণ সংক্রান্ত সমস্যা দেখানো হলে তা বিভ্রান্তিকর হতে পারে। যেমন, কোনও ব্যবহারকারী ইমেল আইডি (যেমন, "user@gm") বা জটিল পাসওয়ার্ড টাইপ করার সময়, সম্পূর্ণ না হওয়া পর্যন্ত ফিল্ডটি টেকনিক্যালি ভুল হিসেবে দেখানো হয়। স্ট্যান্ডার্ড :invalid স্টাইলিংয়ের ফলে সমস্যা সংক্রান্ত স্ট্যাটাস অবিলম্বে দেখা যায়, যা ব্যবহারকারীকে হতাশ করে।

সমাধান

:user-invalid ছদ্ম-শ্রেণি আপনাকে সমস্যা সংক্রান্ত স্ট্যাটাস স্থগিত করার অনুমতি দেয় যতক্ষণ না ব্যবহারকারী কোনও ভ্যালু "কমিট" করেন (ফিল্ড অস্পষ্ট করে) বা ফর্ম জমা দেওয়ার চেষ্টা করেন। এটি নিশ্চিত করে যে ব্যবহারকারী ফিল্ডের সাথে ইন্টার‍্যাক্ট করা শেষ করার পরেই যাচাইকরণ সংক্রান্ত মতামত প্রদান করা হয়।

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

  1. HTML কনস্ট্রেন্ট: ব্রাউজারের বিল্ট-ইন যাচাইকরণ লজিক ট্রিগার করতে type="email", pattern এবং required-এর মতো স্ট্যান্ডার্ড HTML5 অ্যাট্রিবিউট ব্যবহার করুন।
  2. ভিজ্যুয়াল ফিডব্যাক: শুধুমাত্র ইন্টার‍্যাকশনের পরে সমস্যার স্টাইলিং প্রয়োগ করতে :user-invalid ব্যবহার করুন।
  3. ইতিবাচক রিইনফোর্সমেন্ট: প্রয়োজনীয়তা পূরণ হয়ে গেলে, সবুজ রঙের "সফল" ইন্ডিকেটর দেখানোর জন্য বিকল্প হিসেবে :user-valid ব্যবহার করুন।
  4. গ্রেসফুল রিকভারি: ব্যবহারকারী ইনপুট সঠিক ফর্ম্যাটে পরিবর্তন করার সাথে সাথে, :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-এর জন্য ফলব্যাক ও ব্রাউজার সাপোর্ট

ফলব্যাকের জন্য 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. অ্যাক্সেসিবিলিটি:
    • বাধ্যতামূলক: ইনপুটে নিয়মের তালিকা লিঙ্ক করতে aria-describedby ব্যবহার করুন।
    • যা করবেন না: ইনপুট সঠিক না হওয়া পর্যন্ত নিয়মের তালিকা সম্পূর্ণভাবে লুকাবেন না; ব্যবহারকারীকে জানতে হবে যে কী টাইপ করতে হবে!
  2. প্যাটার্ন অ্যাট্রিবিউট সংক্রান্ত সীমাবদ্ধতা: বাধ্যতামূলক: pattern অ্যাট্রিবিউট সম্পূর্ণ ম্যাচ (ইমপ্লাইড ^...$) করে। আপনার পাসওয়ার্ডের রেজেক্স যাতে সম্পূর্ণ স্ট্রিংয়ের জন্য হয় তা নিশ্চিত করুন।
  3. যাচাইকরণের কঠোরতা: মনে রাখবেন যে ব্রাউজারের ডিফল্ট type="email" যাচাইকরণ বেশ অনুমতিমূলক (যেমন, user@localserver পাস হতে পারে)। আপনার যদি আরও কঠোর যাচাইকরণের প্রয়োজন হয়, তাহলে আপনাকে type="email"-এর পাশাপাশি আরও শক্তিশালী যাচাইকরণ লাইব্রেরি বা কাস্টম যাচাইকরণ ফাংশন ব্যবহার করতে হতে পারে।
  4. ফোকাস ম্যানেজমেন্ট: বাধ্যতামূলক: কোনও ব্যবহারকারী ভুল ফিল্ড সহ ফর্ম জমা দিলে, ব্রাউজার অটোমেটিক প্রথম ভুল ফিল্ডে ফোকাস করবে। আপনার :user-invalid স্টাইল অবিলম্বে প্রয়োগ করা হবে কারণ জমা দেওয়ার প্রচেষ্টাকে একটি ইন্টার‍্যাকশন হিসাবে গণনা করা হয়।
  5. একই ধরনের ARIA অভিজ্ঞতা: নেটিভ :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);
});