---
description: Cart drawer component accessibility compliance pattern
globs: *.vue, *.jsx, *.tsx, *.html, *.php, *.js, *.ts, *.liquid
alwaysApply: false
---
# Cart Drawer Component Accessibility Standards

Ensures cart drawer components follow WCAG compliance and ARIA Dialog Pattern specifications for ecommerce applications.

<rule>
name: cart_drawer_accessibility_standards
description: Enforce cart drawer component accessibility standards and ARIA Dialog Pattern compliance
filters:
  - type: file_extension
    pattern: "\\.(vue|jsx|tsx|html|liquid|php|js|ts)$"

actions:
  - type: enforce
    conditions:
      # Cart activator missing aria-haspopup
      - pattern: "(?i)<button[^>]*(?:cart|basket|shopping)[^>]*>"
        pattern_negate: "aria-haspopup=\"dialog\""
        message: "Cart activator buttons must include aria-haspopup='dialog' to inform users a dialog will open."

      # Cart container missing dialog role
      - pattern: "(?i)<(div|section|aside)[^>]*(?:cart|basket|drawer)[^>]*>"
        pattern_negate: "role=\"dialog\""
        message: "Cart drawer containers must have role='dialog' attribute."

      # Cart container missing aria-modal
      - pattern: "(?i)<[^>]*role=\"dialog\"[^>]*(?:cart|basket|drawer)[^>]*>"
        pattern_negate: "aria-modal=\"true\""
        message: "Cart drawer dialog elements must have aria-modal='true' attribute."

      # Cart container missing proper labeling
      - pattern: "(?i)<[^>]*role=\"dialog\"[^>]*(?:cart|basket|drawer)[^>]*>"
        pattern_negate: "(aria-labelledby|aria-label)"
        message: "Cart drawer dialog elements must have either aria-labelledby or aria-label for accessibility."

      # Empty aria-label check
      - pattern: "(?i)<[^>]*role=\"dialog\"[^>]*(?:cart|basket|drawer)[^>]*aria-label=\"\"[^>]*>"
        message: "Cart drawer aria-label should not be empty; provide a meaningful description like 'Shopping Cart'."

      # Close button missing proper functionality
      - pattern: "(?i)<button[^>]*(?:close|dismiss|cancel)[^>]*(?:cart|basket|drawer)[^>]*>"
        pattern_negate: "(onClick|onclick|@click|v-on:click)"
        message: "Cart drawer close buttons should have proper click handlers to close the dialog."

      # Close button missing aria-label
      - pattern: "(?i)<button[^>]*(?:close|dismiss|×|&times;)[^>]*(?:cart|basket|drawer)[^>]*>"
        pattern_negate: "aria-label=\"[^\"]*[Cc]lose[^\"]*\""
        message: "Cart drawer close buttons should have aria-label='Close cart' or similar descriptive text."

      # Missing focus management indicators
      - pattern: "(?i)(?:openCart|showCart|toggleCart|openDrawer)\\s*\\("
        message: "When opening cart drawers, ensure focus management is implemented (focus should move to first focusable element inside the dialog)."

      # Missing checkout button accessibility
      - pattern: "(?i)<button[^>]*(?:checkout|proceed|purchase)[^>]*(?:cart|basket|drawer)[^>]*>"
        pattern_negate: "(aria-label|aria-describedby)"
        message: "Cart drawer checkout buttons should have proper labeling for screen readers."

      # Quantity inputs missing aria-live for screen reader announcements
      - pattern: "(?i)<input[^>]*type=\"number\"[^>]*(?:quantity|qty)[^>]*>"
        pattern_negate: "aria-live=\"polite\""
        message: "Cart quantity inputs must have aria-live='polite' to announce value changes to screen readers."

      # Missing focus management for item removal
      - pattern: "(?i)(?:removeItem|remove.*item|delete.*item)\\s*\\("
        pattern_negate: "focus\\(|focus\\(\\).*close|close.*focus\\(\\"
        message: "When removing cart items, implement focus management to shift focus to a logical location (e.g., close button) for better user experience."

  - type: suggest
    message: |
      **Cart Drawer Component Accessibility Best Practices:**

      **Required ARIA Attributes:**
      - **aria-haspopup='dialog':** Set on cart activator buttons to inform users a dialog will open
      - **role='dialog':** Set on the cart drawer container element
      - **aria-modal='true':** Indicates the cart drawer is modal and traps focus
      - **aria-labelledby:** Reference to visible cart title, OR
      - **aria-label:** Descriptive label like "Shopping Cart" if no visible title exists

      **Keyboard Interaction Requirements:**
      - **Initial Focus:** When cart drawer opens, focus must move to the first focusable element (typically close button)
      - **Tab Cycling:** Tab key should cycle through focusable elements within the cart drawer only
      - **Shift+Tab:** Should cycle backwards through focusable elements within the cart drawer
      - **Escape Key:** Must close the cart drawer and return focus to the activator
      - **Focus Trap:** Focus should be contained within the cart drawer while open

      **Focus Management:**
      - Implement focus trapping to prevent tab navigation outside the cart drawer
      - Return focus to the cart activator when drawer closes
      - Move focus to the close button (first focusable element) when drawer opens
      - Ensure close button is positioned first in DOM order within the dialog container
      - **Item Removal Focus:** When removing cart items, shift focus to the close button for logical positioning
      - **Quantity Changes:** Maintain focus on quantity controls during updates to prevent focus loss

      **Screen Reader Interaction:**
      - Activator should announce "dialog popup" when focused
      - On activation, announce "{Cart label}, dialog" when focus moves to cart drawer
      - Provide clear navigation through cart content
      - Announce return to activator when drawer closes
      - **Quantity Updates:** Use aria-live="polite" on quantity inputs to announce value changes
      - **Item Removal:** Announce item removal with descriptive text (e.g., "Product Name removed from cart")
      - **Dynamic Content:** Ensure all cart state changes are announced to screen readers

      **Structure Requirements:**
      - All interactive elements must be descendants of the cart drawer container
      - Position close button first in DOM order within the cart drawer container
      - Use semantic HTML within the cart drawer (headings, buttons, form labels)
      - Provide clear visual focus indicators
      - Close buttons should use aria-label="Close cart" with &times; entity for visual 'x' icon

      **Implementation Patterns:**

      **Cart Activator Button:**
      ```html
      <button class="cart-activator"
              aria-haspopup="dialog"
              aria-label="View shopping cart"
              onclick="openCartDrawer()">
        <svg aria-hidden="true" width="24" height="24">
          <!-- Cart icon -->
        </svg>
        <span class="cart-count">3</span>
      </button>
      ```

      **Cart Drawer Container:**
      ```html
      <div role="dialog"
           aria-modal="true"
           aria-labelledby="cart-title"
           class="cart-drawer"
           id="cart-drawer">
        <button type="button"
                aria-label="Close cart"
                onclick="closeCartDrawer()"
                class="cart-close">&times;</button>
        <h2 id="cart-title">Shopping Cart</h2>
        <div class="cart-items">
          <!-- Cart items -->
        </div>
        <div class="cart-summary">
          <p>Total: $99.99</p>
          <button aria-label="Proceed to checkout"
                  onclick="proceedToCheckout()">
            Checkout
          </button>
        </div>
      </div>
      ```

      **Quantity Controls with aria-live:**
      ```html
      <div class="quantity-controls">
        <button class="quantity-btn decrease-btn"
                aria-label="Decrease quantity"
                onclick="updateQuantity(itemId, -1)">-</button>
        <input type="number"
               class="quantity-input"
               value="1"
               min="1"
               aria-label="Quantity for Product Name"
               aria-live="polite"
               onchange="setQuantity(itemId, this.value)">
        <button class="quantity-btn increase-btn"
                aria-label="Increase quantity"
                onclick="updateQuantity(itemId, 1)">+</button>
      </div>
      ```

      **Item Removal with Focus Management:**
      ```javascript
      function removeItem(itemId) {
          const item = cartItems.find(item => item.id === itemId);
          if (item) {
              cartItems = cartItems.filter(item => item.id !== itemId);

              // Remove only the specific cart item element
              const cartItem = document.querySelector(`[data-item-id="${itemId}"]`);
              if (cartItem) {
                  cartItem.remove();
              }

              // Update cart state
              updateCartCount();
              updateCartTotal();

              // Announce removal to screen readers
              announceToScreenReader(`${item.name} removed from cart`);

              // Shift focus to close button for logical focus management
              const closeButton = document.querySelector('.cart-close');
              if (closeButton) {
                  closeButton.focus();
              }
          }
      }
      ```

      **JavaScript Considerations:**
      - Implement proper event listeners for Escape key
      - Manage body scroll when cart drawer is open
      - Handle focus restoration on cart drawer close
      - Implement focus trapping within cart drawer
      - Store reference to activator for focus return
      - Handle dynamic cart content updates
      - Ensure proper announcement of cart state changes
      - **Quantity Management:** Update only specific DOM elements instead of re-rendering entire cart
      - **Focus Management:** Shift focus to close button when removing items
      - **Performance:** Avoid unnecessary DOM manipulation to maintain accessibility features

      **Quantity Controls and Item Management:**
      - **aria-live="polite":** Add to all quantity input fields for screen reader announcements
      - **Focus Preservation:** Maintain focus on quantity controls during updates to prevent keyboard navigation issues
      - **Value Announcements:** Screen readers should announce new quantity values when inputs change
      - **Item Removal Focus:** Shift focus to close button after removing items for logical navigation flow
      - **Dynamic Updates:** Avoid full cart re-rendering to preserve focus and improve performance

      **Ecommerce-Specific Considerations:**
      - Announce cart item count changes
      - Provide clear product information in cart items
      - Ensure checkout button is prominently accessible
      - Handle empty cart states appropriately
      - Provide clear pricing and total information
      - Support quantity adjustments with proper labeling
      - Handle cart item removal with confirmation

      **Accessibility Notes:**
      - Cart drawers should not contain critical page navigation
      - Ensure cart content is fully accessible to screen readers
      - Test with screen readers to ensure proper announcement
      - Consider using aria-live regions for dynamic cart updates
      - Provide clear error messages for cart operations
      - Ensure cart drawer works with keyboard-only navigation
      - Test focus management with multiple cart activators

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