---
description: Global scope accessibility standards per WCAG requirements for page language, viewport, title attributes, and skip links
globs: *.vue, *.jsx, *.tsx, *.html, *.php, *.js, *.ts, *.liquid
alwaysApply: true
---

# Global Scope Accessibility Standards

Ensures global accessibility best practices are followed including page language, viewport meta tag, title attribute usage, and skip link implementation for WCAG compliance.

<rule>
name: global_accessibility_standards
description: Enforce global scope accessibility standards per WCAG requirements for page language, viewport, title attributes, and skip links
filters:
  - type: file_extension
    pattern: "\\.(vue|jsx|tsx|html|liquid|php|js|ts)$"

actions:
  - type: enforce
    conditions:
      # Missing lang attribute on html element
      - pattern: "<html[^>]*>"
        pattern_negate: "lang=\"[a-z]{2}(?:-[A-Z]{2})?\""
        message: "HTML element must have lang attribute set to ensure proper pronunciation by assistive technology. Use lang=\"en\" for English or appropriate language code."

      # Invalid language code format
      - pattern: "lang=\"[^a-z]{2}(?:-[^A-Z]{2})?\""
        message: "Language code must follow ISO 639-1 format (e.g., lang=\"en\", lang=\"fr-CA\")."

      # Missing viewport meta tag
      - pattern: "<head[^>]*>"
        pattern_negate: "<meta[^>]*name=\"viewport\""
        message: "Viewport meta tag is required for responsive design and accessibility. Include <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">."

      # Viewport meta tag preventing zoom
      - pattern: "<meta[^>]*name=\"viewport\"[^>]*>"
        pattern_negate: "(maximum-scale=1\\.0|user-scalable=no)"
        message: "Viewport meta tag should not prevent zooming. Avoid maximum-scale=1.0 and user-scalable=no to maintain accessibility for low-vision users."

      # Problematic viewport attributes
      - pattern: "(maximum-scale=1\\.0|user-scalable=no)"
        message: "Viewport meta tag contains attributes that prevent zooming, which creates accessibility issues for low-vision users. Remove maximum-scale=1.0 and user-scalable=no."

      # Title attribute on non-iframe elements
      - pattern: "(?i)<[^>]*title=\"[^\"]+\"[^>]*>"
        pattern_negate: "(iframe|IFRAME)"
        message: "Avoid using title attribute on non-iframe elements as it creates accessibility issues. Use visible text, aria-label, or custom tooltips instead."

      # Missing title on iframe elements
      - pattern: "<iframe[^>]*>"
        pattern_negate: "title=\"[^\"]+\""
        message: "Iframe elements must have title attribute to provide context for screen reader users."

      # Empty or meaningless iframe title
      - pattern: "<iframe[^>]*title=\"\\s*(?:iframe|frame|content|page)\\s*\"[^>]*>"
        message: "Iframe title should be descriptive and meaningful, not generic terms like 'iframe' or 'content'."

      # Missing skip link
      - pattern: "<body[^>]*>"
        pattern_negate: "<a[^>]*href=\"#[^\"]*\"[^>]*(?:skip|main|content)"
        message: "Skip link is required for keyboard navigation accessibility. Add a skip link at the top of the page to bypass repeated content."

      # Skip link not at top of page
      - pattern: "<a[^>]*href=\"#[^\"]*\"[^>]*(?:skip|main|content)[^>]*>"
        pattern_negate: "(<body|<header|<nav)"
        message: "Skip link should be one of the first elements in the document, typically within the header or at the top of the body."

      # Skip link without proper target
      - pattern: "<a[^>]*href=\"#[^\"]*\"[^>]*(?:skip|main|content)[^>]*>"
        pattern_negate: "href=\"#(main|content|primary|skip-content)\""
        message: "Skip link href should target main content area (e.g., href=\"#main\")."

      # Skip link target missing tabindex
      - pattern: "<a[^>]*href=\"#(main|content|primary|skip-content)\"[^>]*>"
        pattern_negate: "<(main|div|section)[^>]*id=\"(main|content|primary|skip-content)\"[^>]*tabindex=\"-1\""
        message: "Skip link target element must have tabindex=\"-1\" to receive keyboard focus when skip link is activated."

      # Skip link without proper CSS classes
      - pattern: "<a[^>]*href=\"#[^\"]*\"[^>]*(?:skip|main|content)[^>]*>"
        pattern_negate: "(class=\"[^\"]*(?:visuallyhidden|sr-only|skip-link)[^\"]*\"|style=\"[^\"]*(?:position:\\s*absolute|clip:\\s*rect|overflow:\\s*hidden)[^\"]*\")"
        message: "Skip link should have CSS classes or styles to hide it visually while keeping it accessible to screen readers and keyboard users."

      # Skip link not properly hidden
      - pattern: "<a[^>]*href=\"#[^\"]*\"[^>]*(?:skip|main|content)[^>]*>"
        pattern_negate: "(display:\\s*none|visibility:\\s*hidden)"
        message: "Skip link should not use display:none or visibility:hidden as these hide it from screen readers. Use visuallyhidden or sr-only classes instead."

  - type: suggest
    message: |
      **Global Scope Accessibility Best Practices:**

      **1. Page Language (WCAG 3.1.1 Language of Page):**
      ```html
      <!-- Good: Proper language declaration -->
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <title>Page Title</title>
        </head>
        <body>
          <!-- Content in English -->
        </body>
      </html>

      <!-- Good: Language toggle with proper lang attributes -->
      <nav>
        <a href="/en" lang="en">English</a>
        <a href="/fr" lang="fr">Français</a>
      </nav>

      <!-- Good: Mixed language content -->
      <p>Welcome to our site. <span lang="fr">Bienvenue sur notre site.</span></p>
      ```

      **Language Code Requirements:**
      - **Primary language:** Set on `<html>` element
      - **Format:** ISO 639-1 (e.g., `lang="en"`, `lang="fr-CA"`)
      - **Mixed content:** Use `lang` attribute on specific elements
      - **Purpose:** Enables proper pronunciation by assistive technology

      **2. Viewport Meta Tag (WCAG 1.3.3 Sensory Characteristics):**
      ```html
      <!-- Good: Accessible viewport meta tag -->
      <meta name="viewport" content="width=device-width, initial-scale=1.0">

      <!-- Good: With additional accessibility features -->
      <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=5.0">

      <!-- Bad: Prevents zooming (accessibility issue) -->
      <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
      ```

      **Viewport Requirements:**
      - **Required:** Must be present for responsive design
      - **Zoom support:** Must allow users to zoom content
      - **Avoid:** `maximum-scale=1.0` and `user-scalable=no`
      - **Purpose:** Enables low-vision users to zoom content

      **3. Title Attribute (General Avoidance):**
      ```html
      <!-- Bad: Title attribute on non-iframe elements -->
      <button title="Click to submit form">Submit</button>
      <a href="/help" title="Get help with your account">Help</a>

      <!-- Good: Visible text instead of title -->
      <button>Submit form</button>
      <a href="/help">Get help with your account</a>

      <!-- Good: Custom accessible tooltip -->
      <button aria-describedby="submit-tooltip">Submit</button>
      <div id="submit-tooltip" class="tooltip" role="tooltip">
        Click to submit your form
      </div>
      ```

      **Title Attribute Guidelines:**
      - **Avoid:** On interactive elements, links, buttons
      - **Exception:** Required on iframe elements
      - **Alternatives:** Visible text, aria-label, aria-describedby
      - **Issues:** Mouse-only, screen reader redundancy, low-vision interference

      **4. Iframe Title Requirements:**
      ```html
      <!-- Good: Iframe with descriptive title -->
      <iframe
        src="https://example.com/embed"
        title="Interactive map showing store locations across the city"
        width="600"
        height="400">
      </iframe>

      <!-- Good: Iframe with meaningful title -->
      <iframe
        src="https://example.com/calendar"
        title="Company event calendar for December 2024"
        width="100%"
        height="500">
      </iframe>

      <!-- Bad: Generic or meaningless title -->
      <iframe
        src="https://example.com/embed"
        title="iframe"
        width="600"
        height="400">
      </iframe>
      ```

      **Iframe Accessibility:**
      - **Required:** Title attribute for context
      - **Content:** Descriptive explanation of iframe purpose
      - **Screen readers:** Need context before entering frame
      - **Navigation:** Ctrl+Opt+Shift+Down to enter iframe (VoiceOver)

      **5. Skip Link Implementation (WCAG 2.4.1 Bypass Blocks):**
      ```html
      <!-- Good: Skip link at top of page -->
      <body>
        <a href="#main" class="skip-link visuallyhidden focusable">
          Skip to main content
        </a>

        <header>
          <nav>
            <!-- Navigation content -->
          </nav>
        </header>

        <main id="main" tabindex="-1">
          <h1>Page Title</h1>
          <!-- Main content -->
        </main>
      </body>
      ```

      **Skip Link Requirements:**
      - **Position:** First element in document (after body)
      - **Target:** Main content area with matching ID
      - **Focus:** Target element must have `tabindex="-1"`
      - **Styling:** Hidden visually, visible on focus
      - **Purpose:** Bypass repeated navigation content

      **6. Skip Link CSS Implementation:**
      ```css
      /* Visually hidden but accessible */
      .visuallyhidden {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
      }

      /* Show on focus for keyboard users */
      .focusable:focus {
        position: static;
        width: auto;
        height: auto;
        padding: 8px 16px;
        margin: 0;
        overflow: visible;
        clip: auto;
        white-space: normal;
        background: #000;
        color: #fff;
        text-decoration: none;
        border-radius: 4px;
        z-index: 1000;
      }

      /* Alternative: Screen reader only class */
      .sr-only {
        position: absolute;
        left: -10000px;
        width: 1px;
        height: 1px;
        overflow: hidden;
      }
      ```

      **Skip Link Best Practices:**
      - **Target elements:** `<main>`, `<h1>`, or main content container
      - **Focus management:** Use `tabindex="-1"` on target
      - **Visual feedback:** Show link when it receives focus
      - **Positioning:** Place at very top of document
      - **Text:** Clear and descriptive (e.g., "Skip to main content")

      **7. Complete Implementation Example:**
      ```html
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Accessible Web Page</title>
          <style>
            .skip-link {
              position: absolute;
              top: -40px;
              left: 6px;
              background: #000;
              color: #fff;
              padding: 8px;
              text-decoration: none;
              border-radius: 4px;
              z-index: 1000;
            }
            .skip-link:focus {
              top: 6px;
            }
          </style>
        </head>
        <body>
          <!-- Skip link -->
          <a href="#main" class="skip-link">Skip to main content</a>

          <!-- Header -->
          <header role="banner">
            <h1>Company Name</h1>
            <nav role="navigation" aria-label="Primary">
              <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/about">About</a></li>
                <li><a href="/contact">Contact</a></li>
              </ul>
            </nav>
          </header>

          <!-- Main content -->
          <main id="main" role="main" tabindex="-1">
            <h2>Welcome to Our Site</h2>
            <p>This is the main content area that the skip link targets.</p>

            <!-- Iframe example -->
            <iframe
              src="https://example.com/embed"
              title="Interactive product demonstration video"
              width="100%"
              height="400">
            </iframe>
          </main>

          <!-- Footer -->
          <footer role="contentinfo">
            <p>&copy; 2024 Company Name</p>
          </footer>
        </body>
      </html>
      ```

      **Testing and Validation:**
      - **Language:** Verify lang attribute is set correctly
      - **Viewport:** Test zoom functionality on mobile devices
      - **Title attributes:** Check for unnecessary usage on non-iframe elements
      - **Iframe titles:** Verify descriptive titles for all iframes
      - **Skip links:** Test keyboard navigation and focus management
      - **Screen readers:** Verify skip link announces correctly
      - **Focus order:** Ensure skip link target receives focus properly

      **Common Mistakes to Avoid:**
      - Missing lang attribute on html element
      - Viewport meta tag preventing zoom
      - Using title attributes on interactive elements
      - Missing or generic iframe titles
      - Skip link not positioned at top of page
      - Skip link target without tabindex="-1"
      - Skip link hidden with display:none
      - Skip link not visible on focus
      - Generic skip link text
      - Skip link targeting wrong element

metadata:
  priority: high
  version: 1.0
</rule>
