All skills
asyrafhussin avatar

/web-design-guidelines

@b73c638

UI/UX best practices and accessibility audit. Use when reviewing UI code, checking accessibility, running accessibility audits, auditing forms, or ensuring web interface best practices. Triggers on "audit accessibility", "check WCAG", "review UI", "check accessibility", "audit design", "review UX", or "check best practices".

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/web-design-guidelines

This session only. Nothing lands on disk.

rulesform-error-display.md

≈2.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Display Form Errors Clearly

Impact: HIGH (WCAG 2.1 Level A - Error identification)

Display form errors clearly and consistently to help users identify and correct mistakes. Error messages should be visible, associated with their fields, and provide actionable guidance.

Incorrect

<!-- ❌ Bad: Poor error display -->
<form>
  <!-- Error message far from input -->
  <div class="errors">
    <p>Email is invalid</p>
    <p>Password is required</p>
  </div>

  <input type="text" name="email" value="bad-email">
  <input type="password" name="password">

  <!-- Generic JavaScript alert -->
  <script>
    function validate() {
      alert('There are errors in your form');
    }
  </script>

  <!-- Error shown only by color change -->
  <input type="text" style="border-color: red;" placeholder="Enter name">

  <!-- Tooltip-only errors (disappear quickly) -->
  <input type="email" title="Please enter a valid email">

  <!-- Clearing the field on error -->
  <input type="text" id="phone" oninvalid="this.value=''">
</form>

Problems:

  • Error messages far from their fields make it hard to identify which input has the problem
  • JavaScript alert() provides no context about specific fields
  • Color-only error indicators are invisible to color-blind users
  • Tooltip-only errors are not persistent and may not be perceived
  • Clearing valid input on error forces users to retype everything

Correct

<!-- ✅ Good: Clear, accessible error display -->
<form id="contact-form" novalidate>
  <!-- Error summary at top of form -->
  <div id="error-summary"
       role="alert"
       class="error-summary"
       hidden>
    <h2>Please correct the following errors:</h2>
    <ul id="error-list">
      <!-- Populated by JavaScript -->
    </ul>
  </div>

  <div class="form-group" id="email-group">
    <label for="email">
      Email Address
      <span class="required" aria-hidden="true">*</span>
    </label>
    <input type="email"
           id="email"
           name="email"
           required
           aria-required="true"
           aria-describedby="email-hint email-error"
           aria-invalid="false">
    <p id="email-hint" class="hint">Enter your work email address</p>
    <p id="email-error" class="field-error" hidden>
      <span class="error-icon" aria-hidden="true">
        <svg width="16" height="16" viewBox="0 0 16 16">
          <circle cx="8" cy="8" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
          <path d="M8 4v5M8 11v1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
        </svg>
      </span>
      <span class="error-text"></span>
    </p>
  </div>

  <div class="form-group" id="phone-group">
    <label for="phone">Phone Number</label>
    <input type="tel"
           id="phone"
           name="phone"
           aria-describedby="phone-error"
           aria-invalid="false">
    <p id="phone-error" class="field-error" hidden>
      <span class="error-icon" aria-hidden="true">
        <svg width="16" height="16" viewBox="0 0 16 16">
          <circle cx="8" cy="8" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
          <path d="M8 4v5M8 11v1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
        </svg>
      </span>
      <span class="error-text"></span>
    </p>
  </div>

  <div class="form-group" id="message-group">
    <label for="message">
      Message
      <span class="required" aria-hidden="true">*</span>
    </label>
    <textarea id="message"
              name="message"
              required
              aria-required="true"
              aria-describedby="message-counter message-error"
              maxlength="500"
              rows="4"></textarea>
    <div class="field-footer">
      <p id="message-counter" class="character-counter">0/500 characters</p>
      <p id="message-error" class="field-error" hidden>
        <span class="error-icon" aria-hidden="true">
          <svg width="16" height="16" viewBox="0 0 16 16">
            <circle cx="8" cy="8" r="7" fill="none" stroke="currentColor" stroke-width="2"/>
            <path d="M8 4v5M8 11v1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
          </svg>
        </span>
        <span class="error-text"></span>
      </p>
    </div>
  </div>

  <button type="submit">Send Message</button>
</form>

<script>
const form = document.getElementById('contact-form');
const errorSummary = document.getElementById('error-summary');
const errorList = document.getElementById('error-list');

form.addEventListener('submit', function(e) {
  e.preventDefault();
  clearAllErrors();

  const errors = validateForm();

  if (errors.length > 0) {
    displayErrors(errors);
  } else {
    // submit form logic here
  }
});

function validateForm() {
  const errors = [];

  // Email validation
  const email = document.getElementById('email');
  if (!email.value) {
    errors.push({ field: 'email', message: 'Email address is required' });
  } else if (!isValidEmail(email.value)) {
    errors.push({ field: 'email', message: 'Enter a valid email address, like name@company.com' });
  }

  // Phone validation (optional but must be valid if provided)
  const phone = document.getElementById('phone');
  if (phone.value && !isValidPhone(phone.value)) {
    errors.push({ field: 'phone', message: 'Enter a valid phone number, like (555) 123-4567' });
  }

  // Message validation
  const message = document.getElementById('message');
  if (!message.value.trim()) {
    errors.push({ field: 'message', message: 'Message is required' });
  } else if (message.value.length < 10) {
    errors.push({ field: 'message', message: 'Message must be at least 10 characters' });
  }

  return errors;
}

function displayErrors(errors) {
  // Build error summary
  errorList.innerHTML = errors.map(error =>
    `<li><a href="#${error.field}">${error.message}</a></li>`
  ).join('');

  errorSummary.hidden = false;

  // Display inline errors
  errors.forEach(error => {
    const input = document.getElementById(error.field);
    const errorEl = document.getElementById(`${error.field}-error`);
    const errorText = errorEl.querySelector('.error-text');

    input.setAttribute('aria-invalid', 'true');
    errorText.textContent = error.message;
    errorEl.hidden = false;

    // Add error class to form group
    document.getElementById(`${error.field}-group`).classList.add('has-error');
  });

  // Focus error summary (or first error field)
  errorSummary.scrollIntoView({ behavior: 'smooth', block: 'start' });
  errorList.querySelector('a').focus();
}

function clearAllErrors() {
  errorSummary.hidden = true;
  errorList.innerHTML = '';

  document.querySelectorAll('.field-error').forEach(el => {
    el.hidden = true;
  });

  document.querySelectorAll('[aria-invalid="true"]').forEach(el => {
    el.setAttribute('aria-invalid', 'false');
  });

  document.querySelectorAll('.has-error').forEach(el => {
    el.classList.remove('has-error');
  });
}
</script>

<style>
.error-summary {
  background: #fef2f2;
  border: 2px solid #dc2626;
  border-radius: 8px;
  padding: 1rem;
  margin-bottom: 1.5rem;
}

.error-summary h2 {
  color: #991b1b;
  font-size: 1rem;
  margin: 0 0 0.5rem;
}

.error-summary ul {
  margin: 0;
  padding-left: 1.5rem;
}

.error-summary a {
  color: #dc2626;
}

.field-error {
  color: #dc2626;
  font-size: 0.875rem;
  margin-top: 0.5rem;
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

.has-error input,
.has-error textarea {
  border-color: #dc2626;
  border-width: 2px;
}

.has-error input:focus,
.has-error textarea:focus {
  outline-color: #dc2626;
  box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.15);
}
</style>

Benefits:

  • Error summary at the top provides an overview with links to each problem field
  • Inline errors next to each field make identification immediate
  • Icons and text alongside color ensure errors are perceivable by all users
  • ARIA attributes link errors programmatically for screen readers
  • User input is preserved on error so nothing needs to be retyped

Reference: WCAG 3.3.1 Error Identification

Source: SKILL.md on GitHub

2 warnings16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides comprehensive guidelines for accessibility and web design audits. It processes user-provided code files to generate compliance reports, which introduces a minor risk of indirect prompt injection if the audited files contain malicious instructions. No evidence of data exfiltration, obfuscation, or unauthorized command execution was found.

  • Socket16d

    2 alerts: gptAnomaly

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    26/27 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at b73c638. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 6 months ago
metadata
{
  "author": "agent-skills",
  "version": "2.1.0"
}

README badge

README badge for asyrafhussin/agent-skills/web-design-guidelines