---
description: Table element accessibility compliance
globs: *.vue, *.jsx, *.tsx, *.html, *.php, *.js, *.ts, *.liquid
alwaysApply: true
---
# Table Element Accessibility Standards

Ensures table elements follow WCAG compliance and provide proper structure for screen reader navigation and data relationships.

<rule>
name: table_accessibility_standards
description: Enforce table element accessibility standards per WCAG 1.3.1 Info and Relationships requirements
filters:
  - type: file_extension
    pattern: "\\.(vue|jsx|tsx|html|liquid|php|js|ts)$"

actions:
  - type: enforce
    conditions:
      # Table headers must use th elements
      - pattern: "(?i)<table[^>]*>.*<td[^>]*>.*</td>.*<td[^>]*>.*</td>"
        pattern_negate: "<th[^>]*>"
        message: "Data tables must use th elements for headers. Use th for header cells and td for data cells."

      # Missing scope attribute on th elements
      - pattern: "(?i)<th[^>]*>"
        pattern_negate: "scope=\"(col|row|colgroup|rowgroup)\""
        message: "Table header cells should have scope attribute set to 'col', 'row', 'colgroup', or 'rowgroup' for proper associations."

      # Data cells not associated with headers
      - pattern: "(?i)<td[^>]*>"
        pattern_negate: "(scope=\"(col|row)\"|headers=\"[^\"]+\"|<th[^>]*scope)"
        message: "Table data cells must be associated with their corresponding header cells via scope or headers attributes."

      # Layout table with headers
      - pattern: "(?i)<table[^>]*class=\"[^\"]*(?:layout|grid|position)[^\"]*\"[^>]*>"
        pattern_negate: "(role=\"table\"|data-table)"
        message: "Layout tables should not contain header elements. Use role='table' for data tables or remove headers from layout tables."

      # Missing caption or accessible name
      - pattern: "(?i)<table[^>]*>"
        pattern_negate: "(<caption|aria-label|aria-labelledby)"
        message: "Data tables should have a caption element or aria-label/aria-labelledby for accessibility."

      # Empty caption
      - pattern: "(?i)<caption[^>]*>\\s*</caption>"
        message: "Table caption should contain meaningful text describing the table's purpose."

      # Generic caption text
      - pattern: "(?i)<caption[^>]*>\\s*(table|data|information)\\s*</caption>"
        message: "Table caption should be specific and descriptive, not generic."

      # Missing table structure elements
      - pattern: "(?i)<table[^>]*>.*<tr[^>]*>.*<td[^>]*>"
        pattern_negate: "(<thead|<tbody|<tfoot)"
        message: "Complex tables should use thead, tbody, and tfoot elements for proper structure."

      # Incorrect role usage
      - pattern: "(?i)role=\"(table|rowgroup|cell|columnheader|rowheader)\""
        pattern_negate: "(<table|<tbody|<thead|<tfoot|<td|<th)"
        message: "Table roles should only be used when native HTML table elements are not available."

      # Missing headers attribute for complex associations
      - pattern: "(?i)<td[^>]*>"
        pattern_negate: "(headers=\"[^\"]+\"|scope=\"(col|row)\")"
        message: "Data cells in complex tables should have headers attribute referencing their associated header IDs."

      # Missing ID on header cells for headers attribute
      - pattern: "(?i)<td[^>]*headers=\"[^\"]+\"[^>]*>"
        pattern_negate: "<th[^>]*id=\"[^\"]+\"[^>]*>"
        message: "Header cells referenced by headers attribute must have unique ID attributes."

      # Nested tables without proper isolation
      - pattern: "(?i)<table[^>]*>.*<table[^>]*>"
        pattern_negate: "(role=\"table\"|aria-label|aria-labelledby)"
        message: "Nested tables should have proper accessible names and structure to avoid confusion."

      # Table without proper row structure
      - pattern: "(?i)<table[^>]*>"
        pattern_negate: "<tr[^>]*>"
        message: "Tables must contain tr (table row) elements for proper structure."

      # Missing table role when using ARIA
      - pattern: "(?i)role=\"(rowgroup|cell|columnheader|rowheader)\""
        pattern_negate: "role=\"table\""
        message: "When using table ARIA roles, the table element must have role='table'."

  - type: suggest
    message: |
      **WCAG 1.3.1 Table Accessibility Requirements:**

      **Table Headers:**
      - **Header Tag:** Table headers MUST be designated with `th` elements
      - **Meaningful Header:** Header text MUST accurately describe the category of corresponding data cells
      - **Header Associations:** Data cells MUST be associated with their corresponding header cells
      - **Scope Attribute:** Use `scope="col"` and `scope="row"` for simple tables
      - **Complex Associations:** Use `headers` and `id` attributes for complex header relationships

      **Tabular Data:**
      - **Tables:** Tabular data SHOULD be represented in a `table` element
      - **Data Relationships:** WCAG 1.3.1 requires data to be associated with their labels

      **Caption Requirements:**
      - **Caption:** Data tables SHOULD have a `caption` element or accessible name
      - **Meaningful Caption:** Caption SHOULD describe the table's identity or purpose
      - **Unique Caption:** Each table SHOULD have a unique caption within the page context

      **Layout Tables:**
      - **Avoid Layout Tables:** Tables SHOULD NOT be used for purely visual layout
      - **No Headers in Layout:** Layout tables MUST NOT contain header elements

      **HTML Markup Requirements:**
      - **Native Elements:** Use semantic HTML `table`, `caption`, `tr`, `th`, `td`, `thead`, `tbody`, `tfoot`
      - **ARIA Roles:** Only use table roles when native HTML is not available

      **Implementation Patterns:**

      **Basic Data Table:**
      ```html
      <table>
        <caption>Monthly Sales Report - Q1 2024</caption>
        <thead>
          <tr>
            <th scope="col">Month</th>
            <th scope="col">Revenue</th>
            <th scope="col">Units Sold</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>January</td>
            <td>$45,000</td>
            <td>1,200</td>
          </tr>
          <tr>
            <td>February</td>
            <td>$52,000</td>
            <td>1,350</td>
          </tr>
        </tbody>
      </table>
      ```

      **Complex Table with Multiple Headers:**
      ```html
      <table>
        <caption>Product Performance by Region and Quarter</caption>
        <thead>
          <tr>
            <th scope="col" rowspan="2">Product</th>
            <th scope="colgroup" colspan="2">Q1 2024</th>
            <th scope="colgroup" colspan="2">Q2 2024</th>
          </tr>
          <tr>
            <th scope="col">North</th>
            <th scope="col">South</th>
            <th scope="col">North</th>
            <th scope="col">South</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th scope="row">Widget A</th>
            <td>150</td>
            <td>200</td>
            <td>175</td>
            <td>225</td>
          </tr>
          <tr>
            <th scope="row">Widget B</th>
            <td>300</td>
            <td>250</td>
            <td>325</td>
            <td>275</td>
          </tr>
        </tbody>
      </table>
      ```

      **Table with Headers Attribute:**
      ```html
      <table>
        <caption>Employee Directory</caption>
        <thead>
          <tr>
            <th id="name">Name</th>
            <th id="department">Department</th>
            <th id="email">Email</th>
            <th id="phone">Phone</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td headers="name">John Smith</td>
            <td headers="department">Engineering</td>
            <td headers="email">john.smith@company.com</td>
            <td headers="phone">555-0101</td>
          </tr>
          <tr>
            <td headers="name">Jane Doe</td>
            <td headers="department">Marketing</td>
            <td headers="email">jane.doe@company.com</td>
            <td headers="phone">555-0102</td>
          </tr>
        </tbody>
      </table>
      ```

      **ARIA Table (when native HTML not available):**
      ```html
      <div role="table" aria-label="Product Inventory">
        <div role="rowgroup">
          <div role="row">
            <div role="columnheader" scope="col">Product</div>
            <div role="columnheader" scope="col">Stock</div>
            <div role="columnheader" scope="col">Price</div>
          </div>
        </div>
        <div role="rowgroup">
          <div role="row">
            <div role="cell">Widget A</div>
            <div role="cell">150</div>
            <div role="cell">$25.00</div>
          </div>
          <div role="row">
            <div role="cell">Widget B</div>
            <div role="cell">200</div>
            <div role="cell">$30.00</div>
          </div>
        </div>
      </div>
      ```

      **Table Structure Guidelines:**

      **Simple Tables:**
      - Use `th` with `scope="col"` for column headers
      - Use `th` with `scope="row"` for row headers
      - Include meaningful `caption` element

      **Complex Tables:**
      - Use `thead`, `tbody`, `tfoot` for structure
      - Use `headers` and `id` attributes for complex associations
      - Consider using `colgroup` and `rowgroup` for grouped headers

      **Layout Tables (Avoid):**
      ```html
      <!-- ❌ Bad: Using table for layout -->
      <table>
        <tr>
          <td>Header</td>
          <td>Content</td>
        </tr>
      </table>

      <!-- ✅ Good: Using CSS for layout -->
      <div class="layout-container">
        <header>Header</header>
        <main>Content</main>
      </div>
      ```

      **Caption Best Practices:**
      ```html
      <!-- ✅ Good: Specific and descriptive -->
      <table>
        <caption>Monthly Sales Performance - Q1 2024</caption>
        <!-- table content -->
      </table>

      <!-- ❌ Bad: Generic caption -->
      <table>
        <caption>Data Table</caption>
        <!-- table content -->
      </table>
      ```

      **Scope Attribute Usage:**
      ```html
      <!-- Column headers -->
      <th scope="col">Product Name</th>
      <th scope="col">Price</th>

      <!-- Row headers -->
      <th scope="row">Widget A</th>
      <th scope="row">Widget B</th>

      <!-- Group headers -->
      <th scope="colgroup" colspan="2">Q1 2024</th>
      <th scope="rowgroup" rowspan="3">Product Category</th>
      ```

      **Testing and Validation:**
      - Test with screen readers to verify header associations
      - Verify table navigation works properly
      - Check that captions are announced correctly
      - Test keyboard navigation through table cells
      - Validate scope attributes are used appropriately
      - Ensure complex tables have proper header associations

      **Common Mistakes to Avoid:**
      - Using `td` elements for headers instead of `th`
      - Missing scope attributes on header cells
      - Using tables for layout purposes
      - Generic or meaningless captions
      - Missing accessible names for tables
      - Incorrect use of ARIA table roles
      - Nested tables without proper isolation
      - Missing header associations in complex tables
      - Using layout tables with header elements

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