Cursor rule
.cursor/rules/combobox-accessibility.mdcCombobox component accessibility compliance pattern
Cursor rules
Quality
40/100
Scores the file, not the repository.Length
927 words
1 headings · 1 code blocksRepository
428
— · pushed 17 days agoLast changed
3 days ago
First indexed 3 days ago.123456# Combobox Component Accessibility Standards78Ensures combobox components follow WCAG compliance and WAI-ARIA Combobox Pattern specifications.910<rule>11name: combobox_accessibility_standards12description: Enforce combobox component accessibility standards and WAI-ARIA Combobox Pattern compliance13filters:14 - type: file_extension15 pattern: "\\.(vue|jsx|tsx|html|liquid|php|js|ts)$"1617actions:18 - type: enforce19 conditions:20 # Combobox role requirement21 - pattern: "(?i)<(div|section)[^>]*(?:combobox|autocomplete)[^>]*>"22 pattern_negate: "role=\"combobox\""23 message: "Combobox containers must have role='combobox' attribute."2425 # aria-expanded requirement26 - pattern: "(?i)<[^>]*role=\"combobox\"[^>]*>"27 pattern_negate: "aria-expanded=\"(true|false)\""28 message: "Combobox elements must have aria-expanded attribute set to 'true' or 'false'."2930 # aria-haspopup requirement31 - pattern: "(?i)<[^>]*role=\"combobox\"[^>]*>"32 pattern_negate: "aria-haspopup=\"listbox\""33 message: "Combobox elements must have aria-haspopup='listbox' attribute."3435 # aria-controls requirement36 - pattern: "(?i)<[^>]*role=\"combobox\"[^>]*>"37 pattern_negate: "aria-controls=\"[^\"]+\""38 message: "Combobox elements must have aria-controls attribute referencing the ID of the associated listbox."3940 # aria-autocomplete requirement41 - pattern: "(?i)<[^>]*role=\"combobox\"[^>]*>"42 pattern_negate: "aria-autocomplete=\"(list|both|inline|none)\""43 message: "Combobox elements must have aria-autocomplete attribute set to 'list', 'both', 'inline', or 'none'."4445 # aria-activedescendant requirement when expanded46 - pattern: "(?i)<[^>]*role=\"combobox\"[^>]*aria-expanded=\"true\"[^>]*>"47 pattern_negate: "aria-activedescendant=\"[^\"]+\""48 message: "Expanded combobox elements must have aria-activedescendant attribute referencing the ID of the active option."4950 # Listbox role requirement51 - pattern: "(?i)<(div|ul)[^>]*(?:listbox|dropdown|popup)[^>]*>"52 pattern_negate: "role=\"listbox\""53 message: "Listbox containers must have role='listbox' attribute."5455 # Option role requirement56 - pattern: "(?i)<(div|li)[^>]*(?:option|item)[^>]*>"57 pattern_negate: "role=\"option\""58 message: "Listbox options must have role='option' attribute."5960 # Option ID requirement for aria-activedescendant61 - pattern: "(?i)<[^>]*role=\"option\"[^>]*>"62 pattern_negate: "id=\"[^\"]+\""63 message: "Listbox options must have unique id attributes for aria-activedescendant to reference them."6465 # aria-selected requirement for options66 - pattern: "(?i)<[^>]*role=\"option\"[^>]*>"67 pattern_negate: "aria-selected=\"(true|false)\""68 message: "Listbox options must have aria-selected attribute set to 'true' or 'false'."6970 # Missing keyboard event handlers71 - pattern: "(?i)<[^>]*role=\"combobox\"[^>]*>"72 pattern_negate: "(onKeyDown|onkeydown|@keydown|v-on:keydown)"73 message: "Combobox elements should handle keyboard events (Arrow keys, Enter, Escape, etc.)."7475 # Missing status region76 - pattern: "(?i)<[^>]*role=\"combobox\"[^>]*>"77 pattern_negate: "aria-controls=\"[^\"]+\".*?<[^>]*role=\"status\""78 message: "Combobox should have a status region to announce available options."7980 - type: suggest81 message: |82 **Combobox Component Accessibility Best Practices:**8384 **Required ARIA Attributes:**85 - **role='combobox':** Set on the input container element86 - **aria-expanded:** 'true' if listbox is visible, 'false' if hidden87 - **aria-haspopup='listbox':** Indicates the combobox has a listbox popup88 - **aria-controls:** Reference to the ID of the associated listbox89 - **aria-autocomplete:** 'list', 'both', 'inline', or 'none' based on behavior90 - **aria-activedescendant:** Reference to the ID of the currently active option (remove when listbox is hidden)91 - **role='listbox':** Set on the popup container element (preferably on a `ul` element)92 - **role='option':** Set on each selectable item in the listbox (preferably on an `li` element)93 - **id:** Unique ID on each option element for `aria-activedescendant` to reference94 - **aria-selected:** 'true' or 'false' on each option95 - **role='status':** Set on a visually hidden element to announce available options9697 **Keyboard Interaction Requirements:**98 - **Down Arrow:** Open listbox and move focus to first option99 - **Up Arrow:** Open listbox and move focus to last option100 - **Enter/Space:** Select focused option and close listbox101 - **Escape:** Close listbox without selection102 - **Tab:** Move focus to next focusable element103 - **Shift+Tab:** Move focus to previous focusable element104 - **Home/End:** Move focus to first/last option105 - **Character Keys:** Filter options based on input106107 **Focus Management:**108 - Focus should remain on the input while navigating options109 - Use aria-activedescendant to indicate the currently focused option110 - Return focus to input after selection or closing111 - Ensure focus is trapped within the combobox while open112113 **Status Region Requirements:**114 - Must announce number of available options when listbox opens115 - Must announce when no options are available116 - Must use proper pluralization ("1 item available" vs "2 items available")117 - Must be visually hidden but available to screen readers118 - Should update dynamically as options are filtered119120 **Semantic HTML Structure:**121 - Use `ul` element for the listbox container122 - Use `li` elements for individual options123 - This provides better semantic structure and is more appropriate for lists124125 **Implementation Example:**126```html127 <div class="combobox-container">128 <label for="combobox-input">Select an option:</label>129 <input type="text"130 id="combobox-input"131 role="combobox"132 aria-expanded="false"133 aria-haspopup="listbox"134 aria-controls="listbox-popup"135 aria-autocomplete="list">136 <ul id="listbox-popup"137 role="listbox"138 hidden>139 <li role="option"140 id="option-1"141 aria-selected="false">142 Option 1143 </li>144 <li role="option"145 id="option-2"146 aria-selected="false">147 Option 2148 </li>149 </ul>150 <div id="listbox-status"151 role="status"152 class="visually-hidden">153 <!-- Status messages will be dynamically updated -->154 </div>155 </div>156157 <style>158 .visually-hidden {159 position: absolute;160 width: 1px;161 height: 1px;162 padding: 0;163 margin: -1px;164 overflow: hidden;165 clip: rect(0, 0, 0, 0);166 white-space: nowrap;167 border: 0;168 }169170 #listbox-popup {171 list-style: none;172 padding: 0;173 margin: 0;174 }175 </style>176177 <script>178 const input = document.getElementById('combobox-input');179 const listbox = document.getElementById('listbox-popup');180 const statusElement = document.getElementById('listbox-status');181182 // Status message handling183 function updateStatusMessage(count) {184 if (count === 0) {185 statusElement.textContent = 'No items available';186 } else {187 statusElement.textContent = `${count} ${count === 1 ? 'item' : 'items'} available`;188 }189 }190191 // Show listbox192 function showListbox() {193 listbox.hidden = false;194 input.setAttribute('aria-expanded', 'true');195 const options = listbox.querySelectorAll('[role="option"]');196 updateStatusMessage(options.length);197 }198199 // Hide listbox200 function hideListbox() {201 listbox.hidden = true;202 input.setAttribute('aria-expanded', 'false');203 input.removeAttribute('aria-activedescendant'); // Important: remove when hiding204 statusElement.textContent = '';205 }206207 // Set active option208 function setActiveOption(optionId) {209 input.setAttribute('aria-activedescendant', optionId);210 }211212 // Example usage:213 // When opening listbox with options:214 showListbox();215 // When setting active option:216 setActiveOption('option-1');217 // When closing listbox:218 hideListbox();219 </script>220```221222 **JavaScript Considerations:**223 - Implement proper event listeners for all keyboard interactions224 - Update ARIA attributes dynamically based on state225 - **Remove `aria-activedescendant` when hiding the listbox** to avoid referencing hidden elements226 - Handle focus management and trapping227 - Implement proper filtering and selection logic228 - Update status messages for all state changes229 - Ensure proper pluralization in status messages230 - Handle edge cases (no matches, empty input, etc.)231232 **Accessibility Notes:**233 - Status region helps screen readers understand available options234 - Proper pluralization improves user experience235 - Clear status messages help users understand the current state236 - Visual feedback should match announced status237 - Test with screen readers to ensure proper announcement238239metadata:240 priority: high241 version: 1.0242</rule>243
Also in Shopify/horizon
Diff this repo’s formatsOne 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?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| Shopify/horizon.cursor/rules/accordion-accessibility.mdc · 428 | Cursor rules | ui | 40/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/animation-accessibility.mdc · 428 | Cursor rules | ui | 40/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/blocks.mdc · 428 | Cursor rules | stylearchtypesdatabase+2 | 62/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/breadcrumb-accessibility.mdc · 428 | Cursor rules | ui | 36/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/carousel-accessibility.mdc · 428 | Cursor rules | ui | 32/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/cart-drawer-accessibility.mdc · 428 | Cursor rules | ui | 40/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/chat-window-accessibility.mdc · 428 | Cursor rules | styleui | 24/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/color-contrast-accessibility.mdc · 428 | Cursor rules | lint-formatui | 44/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/color-swatch-accessibility.mdc · 428 | Cursor rules | ui | 40/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/commit-messages.mdc · 428 | Cursor rules | setuplint-formattypesgit | 62/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/css-standards.mdc · 428 | Cursor rules | stylearchuiperformance+3 | 49/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/disclosure-accessibility.mdc · 428 | Cursor rules | ui | 40/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/dropdown-navigation-accessibility.mdc · 428 | Cursor rules | styleui | 36/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/flip-card-accessibility.mdc · 428 | Cursor rules | styleui | 36/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/form-accessibility.mdc · 428 | Cursor rules | ui | 32/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/javascript-standards.mdc · 428 | Cursor rules | stylearchtypesui+2 | 54/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/landmark-accessibility.mdc · 428 | Cursor rules | ui | 40/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/liquid.mdc · 428 | Cursor rules | buildstyletypesdatabase+2 | 77/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/locales.mdc · 428 | Cursor rules | arch | 49/100 | 3 days ago | |
| Shopify/horizon.cursor/rules/localization.mdc · 428 | Cursor rules | style | 54/100 | 3 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/cart-drawer-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
