RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/Cursor rules/Shopify/horizon

Cursor rule

.cursor/rules/cart-drawer-accessibility.mdc

Cart drawer component accessibility compliance pattern

Cursor rules

Quality

40/100

Scores the file, not the repository.

Length

1,144 words

1 headings · 4 code blocks

Repository

428

— · pushed 17 days ago

Last changed

3 days ago

First indexed 3 days ago.
Shopify/horizon/.cursor/rules/cart-drawer-accessibility.mdcRawGitHub
1---
2description: Cart drawer component accessibility compliance pattern
3globs: *.vue, *.jsx, *.tsx, *.html, *.php, *.js, *.ts, *.liquid
4alwaysApply: false
5---
6# Cart Drawer Component Accessibility Standards
7 
8Ensures cart drawer components follow WCAG compliance and ARIA Dialog Pattern specifications for ecommerce applications.
9 
10<rule>
11name: cart_drawer_accessibility_standards
12description: Enforce cart drawer component accessibility standards and ARIA Dialog Pattern compliance
13filters:
14 - type: file_extension
15 pattern: "\\.(vue|jsx|tsx|html|liquid|php|js|ts)$"
16 
17actions:
18 - type: enforce
19 conditions:
20 # Cart activator missing aria-haspopup
21 - pattern: "(?i)<button[^>]*(?:cart|basket|shopping)[^>]*>"
22 pattern_negate: "aria-haspopup=\"dialog\""
23 message: "Cart activator buttons must include aria-haspopup='dialog' to inform users a dialog will open."
24 
25 # Cart container missing dialog role
26 - pattern: "(?i)<(div|section|aside)[^>]*(?:cart|basket|drawer)[^>]*>"
27 pattern_negate: "role=\"dialog\""
28 message: "Cart drawer containers must have role='dialog' attribute."
29 
30 # Cart container missing aria-modal
31 - pattern: "(?i)<[^>]*role=\"dialog\"[^>]*(?:cart|basket|drawer)[^>]*>"
32 pattern_negate: "aria-modal=\"true\""
33 message: "Cart drawer dialog elements must have aria-modal='true' attribute."
34 
35 # Cart container missing proper labeling
36 - pattern: "(?i)<[^>]*role=\"dialog\"[^>]*(?:cart|basket|drawer)[^>]*>"
37 pattern_negate: "(aria-labelledby|aria-label)"
38 message: "Cart drawer dialog elements must have either aria-labelledby or aria-label for accessibility."
39 
40 # Empty aria-label check
41 - pattern: "(?i)<[^>]*role=\"dialog\"[^>]*(?:cart|basket|drawer)[^>]*aria-label=\"\"[^>]*>"
42 message: "Cart drawer aria-label should not be empty; provide a meaningful description like 'Shopping Cart'."
43 
44 # Close button missing proper functionality
45 - pattern: "(?i)<button[^>]*(?:close|dismiss|cancel)[^>]*(?:cart|basket|drawer)[^>]*>"
46 pattern_negate: "(onClick|onclick|@click|v-on:click)"
47 message: "Cart drawer close buttons should have proper click handlers to close the dialog."
48 
49 # Close button missing aria-label
50 - pattern: "(?i)<button[^>]*(?:close|dismiss|×|&times;)[^>]*(?:cart|basket|drawer)[^>]*>"
51 pattern_negate: "aria-label=\"[^\"]*[Cc]lose[^\"]*\""
52 message: "Cart drawer close buttons should have aria-label='Close cart' or similar descriptive text."
53 
54 # Missing focus management indicators
55 - pattern: "(?i)(?:openCart|showCart|toggleCart|openDrawer)\\s*\\("
56 message: "When opening cart drawers, ensure focus management is implemented (focus should move to first focusable element inside the dialog)."
57 
58 # Missing checkout button accessibility
59 - pattern: "(?i)<button[^>]*(?:checkout|proceed|purchase)[^>]*(?:cart|basket|drawer)[^>]*>"
60 pattern_negate: "(aria-label|aria-describedby)"
61 message: "Cart drawer checkout buttons should have proper labeling for screen readers."
62 
63 # Quantity inputs missing aria-live for screen reader announcements
64 - pattern: "(?i)<input[^>]*type=\"number\"[^>]*(?:quantity|qty)[^>]*>"
65 pattern_negate: "aria-live=\"polite\""
66 message: "Cart quantity inputs must have aria-live='polite' to announce value changes to screen readers."
67 
68 # Missing focus management for item removal
69 - pattern: "(?i)(?:removeItem|remove.*item|delete.*item)\\s*\\("
70 pattern_negate: "focus\\(|focus\\(\\).*close|close.*focus\\(\\"
71 message: "When removing cart items, implement focus management to shift focus to a logical location (e.g., close button) for better user experience."
72 
73 - type: suggest
74 message: |
75 **Cart Drawer Component Accessibility Best Practices:**
76 
77 **Required ARIA Attributes:**
78 - **aria-haspopup='dialog':** Set on cart activator buttons to inform users a dialog will open
79 - **role='dialog':** Set on the cart drawer container element
80 - **aria-modal='true':** Indicates the cart drawer is modal and traps focus
81 - **aria-labelledby:** Reference to visible cart title, OR
82 - **aria-label:** Descriptive label like "Shopping Cart" if no visible title exists
83 
84 **Keyboard Interaction Requirements:**
85 - **Initial Focus:** When cart drawer opens, focus must move to the first focusable element (typically close button)
86 - **Tab Cycling:** Tab key should cycle through focusable elements within the cart drawer only
87 - **Shift+Tab:** Should cycle backwards through focusable elements within the cart drawer
88 - **Escape Key:** Must close the cart drawer and return focus to the activator
89 - **Focus Trap:** Focus should be contained within the cart drawer while open
90 
91 **Focus Management:**
92 - Implement focus trapping to prevent tab navigation outside the cart drawer
93 - Return focus to the cart activator when drawer closes
94 - Move focus to the close button (first focusable element) when drawer opens
95 - Ensure close button is positioned first in DOM order within the dialog container
96 - **Item Removal Focus:** When removing cart items, shift focus to the close button for logical positioning
97 - **Quantity Changes:** Maintain focus on quantity controls during updates to prevent focus loss
98 
99 **Screen Reader Interaction:**
100 - Activator should announce "dialog popup" when focused
101 - On activation, announce "{Cart label}, dialog" when focus moves to cart drawer
102 - Provide clear navigation through cart content
103 - Announce return to activator when drawer closes
104 - **Quantity Updates:** Use aria-live="polite" on quantity inputs to announce value changes
105 - **Item Removal:** Announce item removal with descriptive text (e.g., "Product Name removed from cart")
106 - **Dynamic Content:** Ensure all cart state changes are announced to screen readers
107 
108 **Structure Requirements:**
109 - All interactive elements must be descendants of the cart drawer container
110 - Position close button first in DOM order within the cart drawer container
111 - Use semantic HTML within the cart drawer (headings, buttons, form labels)
112 - Provide clear visual focus indicators
113 - Close buttons should use aria-label="Close cart" with &times; entity for visual 'x' icon
114 
115 **Implementation Patterns:**
116 
117 **Cart Activator Button:**
118```html
119 <button class="cart-activator"
120 aria-haspopup="dialog"
121 aria-label="View shopping cart"
122 onclick="openCartDrawer()">
123 <svg aria-hidden="true" width="24" height="24">
124 <!-- Cart icon -->
125 </svg>
126 <span class="cart-count">3</span>
127 </button>
128```
129 
130 **Cart Drawer Container:**
131```html
132 <div role="dialog"
133 aria-modal="true"
134 aria-labelledby="cart-title"
135 class="cart-drawer"
136 id="cart-drawer">
137 <button type="button"
138 aria-label="Close cart"
139 onclick="closeCartDrawer()"
140 class="cart-close">&times;</button>
141 <h2 id="cart-title">Shopping Cart</h2>
142 <div class="cart-items">
143 <!-- Cart items -->
144 </div>
145 <div class="cart-summary">
146 <p>Total: $99.99</p>
147 <button aria-label="Proceed to checkout"
148 onclick="proceedToCheckout()">
149 Checkout
150 </button>
151 </div>
152 </div>
153```
154 
155 **Quantity Controls with aria-live:**
156```html
157 <div class="quantity-controls">
158 <button class="quantity-btn decrease-btn"
159 aria-label="Decrease quantity"
160 onclick="updateQuantity(itemId, -1)">-</button>
161 <input type="number"
162 class="quantity-input"
163 value="1"
164 min="1"
165 aria-label="Quantity for Product Name"
166 aria-live="polite"
167 onchange="setQuantity(itemId, this.value)">
168 <button class="quantity-btn increase-btn"
169 aria-label="Increase quantity"
170 onclick="updateQuantity(itemId, 1)">+</button>
171 </div>
172```
173 
174 **Item Removal with Focus Management:**
175```javascript
176 function removeItem(itemId) {
177 const item = cartItems.find(item => item.id === itemId);
178 if (item) {
179 cartItems = cartItems.filter(item => item.id !== itemId);
180 
181 // Remove only the specific cart item element
182 const cartItem = document.querySelector(`[data-item-id="${itemId}"]`);
183 if (cartItem) {
184 cartItem.remove();
185 }
186 
187 // Update cart state
188 updateCartCount();
189 updateCartTotal();
190 
191 // Announce removal to screen readers
192 announceToScreenReader(`${item.name} removed from cart`);
193 
194 // Shift focus to close button for logical focus management
195 const closeButton = document.querySelector('.cart-close');
196 if (closeButton) {
197 closeButton.focus();
198 }
199 }
200 }
201```
202 
203 **JavaScript Considerations:**
204 - Implement proper event listeners for Escape key
205 - Manage body scroll when cart drawer is open
206 - Handle focus restoration on cart drawer close
207 - Implement focus trapping within cart drawer
208 - Store reference to activator for focus return
209 - Handle dynamic cart content updates
210 - Ensure proper announcement of cart state changes
211 - **Quantity Management:** Update only specific DOM elements instead of re-rendering entire cart
212 - **Focus Management:** Shift focus to close button when removing items
213 - **Performance:** Avoid unnecessary DOM manipulation to maintain accessibility features
214 
215 **Quantity Controls and Item Management:**
216 - **aria-live="polite":** Add to all quantity input fields for screen reader announcements
217 - **Focus Preservation:** Maintain focus on quantity controls during updates to prevent keyboard navigation issues
218 - **Value Announcements:** Screen readers should announce new quantity values when inputs change
219 - **Item Removal Focus:** Shift focus to close button after removing items for logical navigation flow
220 - **Dynamic Updates:** Avoid full cart re-rendering to preserve focus and improve performance
221 
222 **Ecommerce-Specific Considerations:**
223 - Announce cart item count changes
224 - Provide clear product information in cart items
225 - Ensure checkout button is prominently accessible
226 - Handle empty cart states appropriately
227 - Provide clear pricing and total information
228 - Support quantity adjustments with proper labeling
229 - Handle cart item removal with confirmation
230 
231 **Accessibility Notes:**
232 - Cart drawers should not contain critical page navigation
233 - Ensure cart content is fully accessible to screen readers
234 - Test with screen readers to ensure proper announcement
235 - Consider using aria-live regions for dynamic cart updates
236 - Provide clear error messages for cart operations
237 - Ensure cart drawer works with keyboard-only navigation
238 - Test focus management with multiple cart activators
239 
240metadata:
241 priority: high
242 version: 1.0
243</rule>
244 

Sections

  • Cart Drawer Component Accessibility Standards

What it covers

ui

Glob targeting

  • *.vue
  • *.jsx
  • *.tsx
  • *.html
  • *.php
  • *.js
  • *.ts
  • *.liquid

Format

Cursor rules

The most expressive format here. Many small .mdc files, each with frontmatter declaring when it should load, so a rule about migrations only enters context when a migration is open. Costs the most to maintain and only one editor reads it.

What the corpus says about it

Repository

Owner
Shopify
Language
—
License
—
Archived
no

All configs in this repo

Also in Shopify/horizon

Diff this repo’s formats

One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?

The other instruction files in this repository
RepositoryFormatStackCoversScoreChanged
Shopify/horizon.cursor/rules/accordion-accessibility.mdc · 428Cursor rulesunclassifiedui40/1003 days ago
Shopify/horizon.cursor/rules/animation-accessibility.mdc · 428Cursor rulesunclassifiedui40/1003 days ago
Shopify/horizon.cursor/rules/blocks.mdc · 428Cursor rulesunclassifiedstylearchtypesdatabase+262/1003 days ago
Shopify/horizon.cursor/rules/breadcrumb-accessibility.mdc · 428Cursor rulesunclassifiedui36/1003 days ago
Shopify/horizon.cursor/rules/carousel-accessibility.mdc · 428Cursor rulesunclassifiedui32/1003 days ago
Shopify/horizon.cursor/rules/chat-window-accessibility.mdc · 428Cursor rulesunclassifiedstyleui24/1003 days ago
Shopify/horizon.cursor/rules/color-contrast-accessibility.mdc · 428Cursor rulesunclassifiedlint-formatui44/1003 days ago
Shopify/horizon.cursor/rules/color-swatch-accessibility.mdc · 428Cursor rulesunclassifiedui40/1003 days ago
Shopify/horizon.cursor/rules/commit-messages.mdc · 428Cursor rulesunclassifiedsetuplint-formattypesgit62/1003 days ago
Shopify/horizon.cursor/rules/css-standards.mdc · 428Cursor rulesunclassifiedstylearchuiperformance+349/1003 days ago
Shopify/horizon.cursor/rules/disclosure-accessibility.mdc · 428Cursor rulesunclassifiedui40/1003 days ago
Shopify/horizon.cursor/rules/dropdown-navigation-accessibility.mdc · 428Cursor rulesunclassifiedstyleui36/1003 days ago
Shopify/horizon.cursor/rules/flip-card-accessibility.mdc · 428Cursor rulesunclassifiedstyleui36/1003 days ago
Shopify/horizon.cursor/rules/form-accessibility.mdc · 428Cursor rulesunclassifiedui32/1003 days ago
Shopify/horizon.cursor/rules/javascript-standards.mdc · 428Cursor rulesunclassifiedstylearchtypesui+254/1003 days ago
Shopify/horizon.cursor/rules/landmark-accessibility.mdc · 428Cursor rulesunclassifiedui40/1003 days ago
Shopify/horizon.cursor/rules/liquid.mdc · 428Cursor rulesunclassifiedbuildstyletypesdatabase+277/1003 days ago
Shopify/horizon.cursor/rules/locales.mdc · 428Cursor rulesunclassifiedarch49/1003 days ago
Shopify/horizon.cursor/rules/localization.mdc · 428Cursor rulesunclassifiedstyle54/1003 days ago
Shopify/horizon.cursor/rules/mobile-accessibility-standards.mdc · 428Cursor rulesunclassifiedstyleui36/1003 days ago
Diff against .cursor/rules/accordion-accessibility.mdc Diff against .cursor/rules/animation-accessibility.mdc Diff against .cursor/rules/blocks.mdc Diff against .cursor/rules/breadcrumb-accessibility.mdc Diff against .cursor/rules/carousel-accessibility.mdc Diff against .cursor/rules/chat-window-accessibility.mdc Diff against .cursor/rules/color-contrast-accessibility.mdc Diff against .cursor/rules/color-swatch-accessibility.mdc Diff against .cursor/rules/commit-messages.mdc Diff against .cursor/rules/css-standards.mdc Diff against .cursor/rules/disclosure-accessibility.mdc Diff against .cursor/rules/dropdown-navigation-accessibility.mdc Diff against .cursor/rules/flip-card-accessibility.mdc Diff against .cursor/rules/form-accessibility.mdc Diff against .cursor/rules/javascript-standards.mdc Diff against .cursor/rules/landmark-accessibility.mdc Diff against .cursor/rules/liquid.mdc Diff against .cursor/rules/locales.mdc Diff against .cursor/rules/localization.mdc Diff against .cursor/rules/mobile-accessibility-standards.mdc
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack