التسميات والارتباطات

مثال سيء

تسجيل الدخول

تذكرني
<!-- ❌ سيء: تسميات مفقودة -->
<form>
  <h4>تسجيل الدخول</h4>

  <!-- لا توجد تسمية مرتبطة -->
  <input
    type="email"
    placeholder="بريدك الإلكتروني">

  <!-- لا توجد تسمية مرتبطة، لا يوجد إكمال تلقائي -->
  <input
    type="password"
    placeholder="كلمة المرور">

  <!-- مربع اختيار غير مرتبط -->
  <input type="checkbox">
  <span>تذكرني</span>

  <button type="submit">تسجيل الدخول</button>
</form>

مثال جيد

تسجيل الدخول

لن نشارك بريدك الإلكتروني أبدًا
8 أحرف على الأقل مع أحرف كبيرة وأرقام
<!-- ✅ جيد: تسميات صريحة ومرتبطة -->
<form>
  <h4>تسجيل الدخول</h4>

  <!-- تسمية مرتبطة عبر for/id -->
  <label for="email-good">عنوان البريد الإلكتروني</label>
  <input
    type="email"
    id="email-good"
    placeholder="example@domain.com"
    required
    aria-describedby="email-help"
    autocomplete="email">
  <div id="email-help">
    لن نشارك بريدك الإلكتروني أبدًا
  </div>

  <!-- تسمية مع تعليمات -->
  <label for="password-good">كلمة المرور</label>
  <input
    type="password"
    id="password-good"
    required
    aria-describedby="password-help"
    autocomplete="current-password">
  <div id="password-help">
    8 أحرف على الأقل مع أحرف كبيرة وأرقام
  </div>

  <!-- مربع اختيار مرتبط بشكل صحيح -->
  <input type="checkbox" id="remember-good">
  <label for="remember-good">تذكرني</label>

  <button type="submit">تسجيل الدخول</button>
</form>

الشرح: يجب أن يكون لكل حقل نموذج تسمية صريحة مرتبطة بشكل صحيح. العناصر النائبة لا تحل محل التسميات.

التحقق من الصحة ورسائل الخطأ

مثال سيء

الاشتراك في النشرة الإخبارية

<!-- ❌ سيء: أخطاء لم يتم الإعلان عنها بشكل جيد -->
<form @submit.prevent="submitBadForm">
  <h4>الاشتراك في النشرة الإخبارية</h4>

  <!-- لا يوجد ارتباط تسمية-إدخال -->
  <label>الاسم</label>
  <input
    type="text"
    v-model="badForm.name"
    :class="{ 'error': submitted && !badForm.name }">

  <!-- خطأ مرئي فقط -->
  <label>البريد الإلكتروني</label>
  <input
    type="email"
    v-model="badForm.email"
    :class="{ 'error': submitted && !isValidEmail(badForm.email) }">

  <!-- لا توجد معلومات خطأ -->
  <label>العمر</label>
  <input
    type="number"
    v-model="badForm.age"
    :class="{ 'error': submitted && badForm.age < 16 }">

  <!-- رسالة خطأ عامة وغير مفيدة -->
  <div v-if="submitted && badFormErrors.length">
    ❌ يرجى تصحيح الأخطاء
  </div>

  <button type="submit">اشترك</button>
</form>

مثال جيد

الاشتراك في النشرة الإخبارية

يجب أن تكون 16 عامًا على الأقل
<!-- ✅ جيد: أخطاء مرتبطة بوضوح -->
<form @submit.prevent="submitGoodForm" novalidate>
  <h4>الاشتراك في النشرة الإخبارية</h4>

  <!-- ملخص الأخطاء مع التنقل -->
  <div
    v-if="submitted && goodFormErrors.length"
    role="alert"
    aria-labelledby="error-summary-title">
    <h5 id="error-summary-title">أخطاء يجب تصحيحها:</h5>
    <ul>
      <li v-for="error in goodFormErrors" :key="error.field">
        <a :href="`#${error.field}-good-form`">
          
        </a>
      </li>
    </ul>
  </div>

  <!-- حقل مع خطأ محدد مرتبط -->
  <label for="name-good-form">الاسم الكامل *</label>
  <input
    type="text"
    id="name-good-form"
    v-model="goodForm.name"
    required
    aria-invalid="submitted && !goodForm.name"
    aria-describedby="name-error">
  <div
    v-if="submitted && !goodForm.name"
    id="name-error"
    role="alert">
    ❌ الاسم مطلوب
  </div>

  <button type="submit">اشترك</button>
</form>

الشرح: يجب الإعلان عن الأخطاء بوضوح، وربطها بالحقول ذات الصلة، وتوفير تعليمات دقيقة للتصحيح.

مجموعات الحقول مع aria-labelledby

مثال سيء

التفضيلات

<!-- ❌ سيء: بنية غير منظمة -->
<form>
  <h4>التفضيلات</h4>

  <!-- عناصر مختلطة بدون منطق -->
  <div>
    <input type="radio" name="contact-bad"
           id="email-contact-bad" value="email">
    <label for="email-contact-bad">البريد الإلكتروني</label>

    <input type="checkbox" id="newsletter-bad"
           value="newsletter">
    <label for="newsletter-bad">النشرة الإخبارية</label>
  </div>

  <div>
    <input type="radio" name="contact-bad"
           id="phone-contact-bad" value="phone">
    <label for="phone-contact-bad">الهاتف</label>

    <!-- حقل نصي بدون سياق -->
    <input type="text" placeholder="الاسم">
  </div>

  <div>
    <input type="checkbox" id="offers-bad" value="offers">
    <label for="offers-bad">العروض</label>

    <input type="radio" name="contact-bad"
           id="sms-contact-bad" value="sms">
    <label for="sms-contact-bad">الرسائل القصيرة</label>
  </div>

  <!-- اختيار بدون سياق -->
  <select>
    <option>اختر...</option>
    <option>يومي</option>
    <option>أسبوعي</option>
  </select>

  <button type="submit">موافق</button>
</form>

مثال جيد

تفضيلات الاتصال

المعلومات الشخصية
اسمك الكامل كما سيظهر في اتصالاتنا
سنستخدم هذا البريد الإلكتروني لجميع اتصالاتنا
طريقة الاتصال المفضلة *
أنواع الاتصالات

اختر أنواع الاتصالات التي ترغب في تلقيها

تكرار الاتصالات
يحدد الحد الأقصى لتكرار رسائلنا
<!-- ✅ جيد: مجموعات منطقية مع aria-labelledby -->
<form>
  <h4>تفضيلات الاتصال</h4>

  <!-- قسم المعلومات الشخصية -->
  <div role="group" aria-labelledby="personal-info-title">
    <h5 id="personal-info-title">
      المعلومات الشخصية
    </h5>

    <label for="name-good">الاسم الكامل *</label>
    <input
      type="text"
      id="name-good"
      name="name"
      required
      aria-required="true"
      aria-describedby="name-desc">
    <span id="name-desc">
      اسمك الكامل كما سيظهر في اتصالاتنا
    </span>
  </div>

  <!-- مجموعة أزرار الراديو -->
  <div
    role="radiogroup"
    aria-labelledby="contact-method-title"
    aria-required="true">
    <h5 id="contact-method-title">
      طريقة الاتصال المفضلة *
    </h5>

    <input
      type="radio"
      name="contact-good"
      id="email-contact-good"
      value="email"
      required>
    <label for="email-contact-good">البريد الإلكتروني</label>

    <input
      type="radio"
      name="contact-good"
      id="phone-contact-good"
      value="phone"
      required>
    <label for="phone-contact-good">الهاتف</label>
  </div>

  <!-- مجموعة مربعات الاختيار -->
  <div role="group" aria-labelledby="comm-types-title">
    <h5 id="comm-types-title">أنواع الاتصالات</h5>
    <p id="comm-types-desc">
      اختر أنواع الاتصالات التي ترغب في تلقيها
    </p>

    <input
      type="checkbox"
      id="newsletter-good"
      value="newsletter"
      aria-describedby="comm-types-desc">
    <label for="newsletter-good">النشرة الإخبارية</label>
  </div>

  <button type="submit">
    حفظ التفضيلات
  </button>
</form>

الشرح: يجب ربط مجموعات الحقول ذات الصلة بعناوينها عبر aria-labelledby لإنشاء علاقات دلالية واضحة، خاصة لأزرار الراديو ومربعات الاختيار.

نموذج معقد مع التحقق في الوقت الفعلي

مثال سيء

إنشاء حساب

<!-- ❌ سيء: تحقق متطفل -->
<form>
  <h4>إنشاء حساب</h4>

  <!-- تحقق فوري على كل ضغطة مفتاح -->
  <label>اسم المستخدم</label>
  <input
    type="text"
    v-model="complexBadForm.username"
    @input="validateUsernameBad"
    :class="{ 'error': usernameBadError }">
  <!-- خطأ يظهر/يختفي باستمرار -->
  <div v-if="usernameBadError">
    
  </div>

  <!-- لا يوجد ارتباط مع aria-describedby -->
  <label>البريد الإلكتروني</label>
  <input
    type="email"
    v-model="complexBadForm.email"
    @input="validateEmailBad"
    :class="{ 'error': emailBadError }">
  <div v-if="emailBadError"></div>

  <!-- رسائل خطأ قصيرة جدًا وغير مفيدة -->
  <!-- لا يوجد إكمال تلقائي لمساعدة مديري كلمات المرور -->
  <label>كلمة المرور</label>
  <input
    type="password"
    v-model="complexBadForm.password"
    @input="validatePasswordBad"
    :class="{ 'error': passwordBadError }">
  <div v-if="passwordBadError"></div>

  <button type="submit">إنشاء حساب</button>
</form>

مثال جيد

إنشاء حساب

المتطلبات:
  • 3 أحرف على الأقل
  • أحرف وأرقام وشرطة سفلية فقط
قوة كلمة المرور:
8+ أحرف
حرف كبير
رقم
حرف خاص
<!-- ✅ جيد: تحقق محترم مع ردود الفعل -->
<form>
  <h4>إنشاء حساب</h4>

  <!-- التحقق عند blur، وليس على input -->
  <label for="username-complex">اسم المستخدم *</label>
  <input
    type="text"
    id="username-complex"
    v-model="complexGoodForm.username"
    @blur="validateUsernameGood"
    :class="{ error: usernameGoodError,
              success: usernameGoodValid }"
    aria-describedby="username-requirements username-feedback"
    aria-invalid="!!usernameGoodError"
    required>

  <!-- تعليمات واضحة -->
  <div id="username-requirements">
    <h6>المتطلبات:</h6>
    <ul>
      <li :class="{ valid: complexGoodForm.username.length >= 3 }">
        3 أحرف على الأقل
      </li>
      <li :class="{ valid: /^[a-zA-Z0-9_]+$/.test(username) }">
        أحرف وأرقام وشرطة سفلية فقط
      </li>
    </ul>
  </div>

  <!-- ردود فعل يمكن الوصول إليها -->
  <div
    v-if="usernameGoodError"
    id="username-feedback"
    role="alert"
    aria-live="polite">
    ❌ 
  </div>
  <div
    v-else-if="usernameGoodValid"
    id="username-feedback"
    role="status"
    aria-live="polite">
    ✅ اسم المستخدم متاح
  </div>

  <!-- مؤشر قوة كلمة المرور -->
  <label for="password-complex">كلمة المرور *</label>
  <input
    type="password"
    id="password-complex"
    v-model="complexGoodForm.password"
    @input="validatePasswordGood"
    aria-describedby="password-strength"
    autocomplete="new-password"
    required>

  <div id="password-strength">
    <h6>قوة كلمة المرور:</h6>
    <div class="strength-indicator">
      <div
        class="strength-bar"
        :class="`strength-${passwordStrength}`"
        :style="{ width: `${passwordStrength * 25}%` }">
      </div>
    </div>
  </div>

  <button type="submit" :disabled="!isFormValid">
    إنشاء حساب
  </button>
</form>

الشرح: بالنسبة للنماذج المعقدة، يمكن أن يساعد التحقق في الوقت الفعلي، ولكن يجب تنفيذه بطريقة غير متطفلة ويمكن الوصول إليها.