Cursor rule
.cursor/rules/product-media-gallery-accessibility.mdcEnforce product media gallery component accessibility standards and proper landmark structure for media galleries
Cursor rules
Quality
32/100
Scores the file, not the repository.Length
2,080 words
1 headings · 6 code blocksRepository
428
— · pushed 17 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# Product Media Gallery Component Accessibility Standards89Ensures product media gallery components follow WCAG compliance and provide proper accessibility for image, video, and 3D model galleries with screen reader support and keyboard navigation.1011<rule>12name: product_media_gallery_accessibility_standards13description: Enforce product media gallery component accessibility standards and proper landmark structure for media galleries14filters:15 - type: file_extension16 pattern: "\\.(vue|jsx|tsx|html|liquid|php|js|ts)$"1718actions:19 - type: enforce20 conditions:21 # Missing gallery container landmark role22 - pattern: "(?i)<(div|section)[^>]*(?:gallery|media.*gallery|product.*gallery)[^>]*>"23 pattern_negate: "role=\"region\""24 message: "Product media gallery containers must have role='region' to provide proper landmark structure."2526 # Missing gallery landmark aria-labelledby27 - pattern: "(?i)<[^>]*role=\"region\"[^>]*(?:gallery|media.*gallery|product.*gallery)[^>]*>"28 pattern_negate: "aria-labelledby=\"[^\"]+\""29 message: "Gallery region must have aria-labelledby referencing a heading element for proper screen reader identification."3031 # Missing gallery landmark heading32 - pattern: "(?i)<[^>]*role=\"region\"[^>]*(?:gallery|media.*gallery|product.*gallery)[^>]*>"33 pattern_negate: "<h[1-6][^>]*id=\"[^\"]+\"[^>]*>"34 message: "Gallery region must contain a heading element with unique ID for aria-labelledby reference."3536 # Missing gallery viewer container37 - pattern: "(?i)<[^>]*role=\"region\"[^>]*(?:gallery|media.*gallery|product.*gallery)[^>]*>"38 pattern_negate: "<(div|section)[^>]*(?:viewer|display|main.*image)[^>]*>"39 message: "Gallery region must contain a gallery viewer container for displaying selected media."4041 # Gallery viewer missing proper image alt text42 - pattern: "(?i)<img[^>]*(?:gallery|viewer|main.*image)[^>]*>"43 pattern_negate: "alt=\"[^\"]+\""44 message: "Gallery viewer images must have descriptive alt text via alt attribute for screen reader accessibility."4546 # Hidden media not properly hidden from assistive technology47 - pattern: "(?i)<(img|video|iframe)[^>]*(?:gallery|media)[^>]*>"48 pattern_negate: "(hidden|aria-hidden=\"true\"|display.*none|visibility.*hidden)"49 message: "Hidden media items must use hidden attribute to remove them from both visual and assistive technology access."5051 # Thumbnail buttons missing button element structure52 - pattern: "(?i)<(div|span)[^>]*(?:thumbnail|thumb)[^>]*>"53 pattern_negate: "(<button|role=\"button\")"54 message: "Thumbnail media selectors must use button elements or have role='button' for proper keyboard accessibility."5556 # Thumbnail buttons missing descriptive aria-label57 - pattern: "(?i)<button[^>]*(?:thumbnail|thumb)[^>]*>"58 pattern_negate: "aria-label=\"[^\"]*[Ll]oad[^\"]*[Mm]edia[^\"]*[Gg]allery[^\"]*[Vv]iewer[^\"]*\""59 message: "Thumbnail buttons must have descriptive aria-label like 'Load media 1 into gallery viewer' for screen reader context."6061 # Missing aria-current on active thumbnail62 - pattern: "(?i)<button[^>]*(?:thumbnail|thumb)[^>]*>"63 pattern_negate: "aria-current=\"(true|false)\""64 message: "Thumbnail buttons must have aria-current attribute to indicate which media is currently loaded in the viewer."6566 # Missing aria-describedby on thumbnail buttons67 - pattern: "(?i)<button[^>]*(?:thumbnail|thumb)[^>]*>"68 pattern_negate: "aria-describedby=\"[^\"]+\""69 message: "Thumbnail buttons must have aria-describedby referencing the underlying media ID for alt text context."7071 # Missing aria-controls on thumbnail buttons72 - pattern: "(?i)<button[^>]*(?:thumbnail|thumb)[^>]*>"73 pattern_negate: "aria-controls=\"[^\"]+\""74 message: "Thumbnail buttons must have aria-controls referencing the gallery viewer container ID."7576 # Missing live region for media loading announcements77 - pattern: "(?i)<(div|section)[^>]*(?:gallery|media.*gallery|product.*gallery)[^>]*>"78 pattern_negate: "role=\"status\""79 message: "Gallery must include a live region with role='status' for announcing media loading completion to screen readers."8081 # Live region with unnecessary aria-hidden attribute82 - pattern: "(?i)<[^>]*role=\"status\"[^>]*(?:gallery|media)[^>]*aria-hidden=\"true\"[^>]*>"83 message: "Gallery live region should not use aria-hidden='true' when content is dynamically managed through JavaScript."8485 # Live region with redundant aria-live attribute86 - pattern: "(?i)<[^>]*role=\"status\"[^>]*aria-live=\"[^\"]*\"[^>]*>"87 message: "Live regions with role='status' should not include aria-live attribute as it's redundant and unnecessary."8889 # Live region with unnecessary aria-hidden attribute90 - pattern: "(?i)<[^>]*role=\"status\"[^>]*aria-hidden=\"true\"[^>]*>"91 message: "Live regions with role='status' should not use aria-hidden='true' when content is dynamically managed through JavaScript."9293 # Missing list structure for thumbnail grid layout94 - pattern: "(?i)<(div|section)[^>]*(?:thumbnail|thumb)[^>]*>"95 pattern_negate: "(<ul|<ol|<li)"96 message: "Desktop thumbnail layouts should use list structure (ul/ol/li) to convey the number of available media items."9798 # Mobile slider missing navigation controls99 - pattern: "(?i)<(div|section)[^>]*(?:mobile.*slider|slider.*mobile|thumbnail.*slider)[^>]*>"100 pattern_negate: "(previous|next|arrow|navigation)"101 message: "Mobile thumbnail sliders must include previous/next navigation controls for accessing hidden thumbnails."102103 # Mobile slider missing proper hiding of off-screen content104 - pattern: "(?i)<(div|section)[^>]*(?:mobile.*slider|slider.*mobile|thumbnail.*slider)[^>]*>"105 pattern_negate: "(hidden|aria-hidden=\"true\"|display.*none)"106 message: "Mobile slider content not currently visible must be hidden from both visual and assistive technology access."107108 # Zoom button missing proper labeling109 - pattern: "(?i)<button[^>]*(?:zoom|expand|enlarge)[^>]*(?:gallery|viewer)[^>]*>"110 pattern_negate: "aria-label=\"[^\"]*[Zz]oom[^\"]*[Ii]mage[^\"]*\""111 message: "Gallery zoom buttons must have aria-label='Zoom image' for proper screen reader identification."112113 # Zoom button missing modal functionality114 - pattern: "(?i)<button[^>]*(?:zoom|expand|enlarge)[^>]*(?:gallery|viewer)[^>]*>"115 pattern_negate: "(onClick|onclick|@click|v-on:click|role=\"button\")"116 message: "Gallery zoom buttons must have proper click handlers to launch modal windows for expanded viewing."117118 # Zoom button missing aria-haspopup119 - pattern: "(?i)<button[^>]*(?:zoom|expand|enlarge)[^>]*(?:gallery|viewer)[^>]*>"120 pattern_negate: "aria-haspopup=\"dialog\""121 message: "Gallery zoom buttons must have aria-haspopup='dialog' to indicate they open a dialog popup."122123 # Missing focus management for media changes124 - pattern: "(?i)<button[^>]*(?:thumbnail|thumb)[^>]*>"125 pattern_negate: "(onClick|onclick|@click|v-on:click)"126 message: "Thumbnail buttons must have click handlers to load media into the gallery viewer and manage focus appropriately."127128 # Missing focus restoration on modal close129 - pattern: "(?i)<button[^>]*(?:close|dismiss)[^>]*(?:modal|dialog)[^>]*>"130 pattern_negate: "(onClick|onclick|@click|v-on:click)"131 message: "Modal close buttons should have proper click handlers to close the dialog and restore focus to the activator."132133 # Gallery viewer missing proper ID for aria-controls reference134 - pattern: "(?i)<(div|section)[^>]*(?:viewer|display|main.*image)[^>]*>"135 pattern_negate: "id=\"[^\"]+\""136 message: "Gallery viewer container must have unique ID for aria-controls reference from thumbnail buttons."137138 # Thumbnail media missing proper ID for aria-describedby reference139 - pattern: "(?i)<(img|video|iframe)[^>]*(?:thumbnail|thumb)[^>]*>"140 pattern_negate: "id=\"[^\"]+\""141 message: "Thumbnail media items must have unique IDs for aria-describedby reference from thumbnail buttons."142143 - type: suggest144 message: |145 **Product Media Gallery Component Accessibility Best Practices:**146147 **1. Gallery Container Structure:**148```html149 <!-- Gallery region landmark -->150 <div role="region" aria-labelledby="gallery-heading" class="product-gallery">151 <h2 id="gallery-heading" class="visually-hidden">Gallery Viewer</h2>152 <!-- Gallery viewer for main media display -->153 <div id="gallery-viewer" class="gallery-viewer">154 <img src="product-1.jpg"155 alt="Product front view showing design details"156 class="main-image">157158 <!-- Optional zoom button -->159 <button type="button"160 class="zoom-button"161 aria-label="Zoom image"162 aria-haspopup="dialog"163 onclick="openImageModal()">164 <svg aria-hidden="true" width="24" height="24">165 <!-- Zoom icon -->166 </svg>167 </button>168 </div>169170 <!-- Thumbnail navigation -->171 <div class="thumbnail-section">172 <ul class="thumbnail-list">173 <li>174 <button type="button"175 class="thumbnail-button"176 aria-label="Load media 1 into gallery viewer"177 aria-current="true"178 aria-describedby="media-1"179 aria-controls="gallery-viewer"180 onclick="loadMedia(1)">181 <img src="product-1-thumb.jpg"182 id="media-1"183 alt="Product front view thumbnail"184 class="thumbnail-image">185 </button>186 </li>187 <li>188 <button type="button"189 class="thumbnail-button"190 aria-label="Load media 2 into gallery viewer"191 aria-current="false"192 aria-describedby="media-2"193 aria-controls="gallery-viewer"194 onclick="loadMedia(2)">195 <img src="product-2-thumb.jpg"196 id="media-2"197 alt="Product side view thumbnail"198 class="thumbnail-image">199 </button>200 </li>201 </ul>202 </div>203204 <!-- Live region for announcements -->205 <div class="visually-hidden"206 role="status"207 id="gallery-announcement">208 </div>209 </div>210```211212 **2. JavaScript Media Loading Function:**213```javascript214 function loadMedia(mediaIndex) {215 const galleryViewer = document.getElementById('gallery-viewer');216 const thumbnailButtons = document.querySelectorAll('.thumbnail-button');217 const announcement = document.getElementById('gallery-announcement');218219 // Update aria-current states220 thumbnailButtons.forEach((button, index) => {221 button.setAttribute('aria-current', index === mediaIndex - 1 ? 'true' : 'false');222 });223224 // Load new media into viewer225 const newMedia = getMediaByIndex(mediaIndex);226 galleryViewer.innerHTML = `227 <img src="${newMedia.src}"228 alt="${newMedia.alt}"229 class="main-image">230 <button type="button"231 class="zoom-button"232 aria-label="Zoom image"233 onclick="openImageModal()">234 <svg aria-hidden="true" width="24" height="24">235 <!-- Zoom icon -->236 </svg>237 </button>238 `;239240 // Announce media change241 announcement.textContent = `Media ${mediaIndex} is now available in gallery view`;242243 // Hide announcement after 3 seconds244 setTimeout(() => {245 announcement.textContent = '';246 }, 3000);247248 // Maintain focus on thumbnail button249 event.target.focus();250 }251```252253 **3. Unified Thumbnail System Implementation:**254```html255 <!-- Single thumbnail list for both desktop and mobile -->256 <div class="thumbnail-container">257 <button type="button"258 class="slider-nav prev"259 aria-label="Previous thumbnails"260 onclick="slideThumbnails('prev')">261 <svg aria-hidden="true" viewBox="0 0 24 24">262 <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>263 </svg>264 </button>265266 <ul class="thumbnail-list" id="thumbnails">267 <li>268 <button type="button"269 class="thumbnail-button"270 aria-label="Load media 1 into gallery viewer"271 aria-current="true"272 aria-describedby="media-1"273 aria-controls="gallery-viewer"274 onclick="loadMedia(1)">275 <img src="product-1-thumb.jpg"276 id="media-1"277 alt="Product front view thumbnail"278 class="thumbnail-image">279 </button>280 </li>281 <li>282 <button type="button"283 class="thumbnail-button"284 aria-label="Load media 2 into gallery viewer"285 aria-current="false"286 aria-describedby="media-2"287 aria-controls="gallery-viewer"288 onclick="loadMedia(2)">289 <img src="product-2-thumb.jpg"290 id="media-2"291 alt="Product side view thumbnail"292 class="thumbnail-image">293 </button>294 </li>295 <!-- Additional thumbnails as needed -->296 </ul>297298 <button type="button"299 class="slider-nav next"300 aria-label="Next thumbnails"301 onclick="slideThumbnails('next')">302 <svg aria-hidden="true" viewBox="0 0 24 24">303 <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>304 </svg>305 </button>306 </div>307```308309 **4. CSS for Unified Thumbnail System:**310```css311 /* Thumbnail container with navigation */312 .thumbnail-container {313 position: relative;314 display: flex;315 align-items: center;316 justify-content: center;317 gap: 1rem;318 max-width: 100%;319 }320321 /* Desktop grid layout */322 .thumbnail-list {323 display: grid;324 grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));325 gap: 12px;326 list-style: none;327 margin: 0 auto;328 padding: 0;329 flex-wrap: wrap;330 transition: transform 0.3s ease-in-out;331 text-align: center;332 }333334 /* Mobile slider layout */335 @media screen and (max-width: 749px) {336 .thumbnail-container {337 overflow: hidden;338 padding: 0 50px;339 display: flex;340 align-items: center;341 justify-content: center;342 }343344 .thumbnail-list {345 flex-wrap: nowrap;346 justify-content: center;347 gap: 8px;348 min-width: max-content;349 transform: translateX(0);350 position: relative;351 left: 50%;352 margin-left: -50%;353 }354355 .slider-nav {356 display: block;357 position: absolute;358 top: 50%;359 transform: translateY(-50%);360 z-index: 2;361 }362363 .slider-nav.prev {364 left: 0;365 }366367 .slider-nav.next {368 right: 0;369 }370 }371372 /* Hide navigation on desktop */373 @media screen and (min-width: 750px) {374 .slider-nav {375 display: none;376 }377 }378```379380 **5. Modal Window Integration:**381```javascript382 function openImageModal() {383 const galleryViewer = document.getElementById('gallery-viewer');384 const currentImage = galleryViewer.querySelector('.main-image');385 const zoomButton = document.querySelector('.zoom-button');386387 // Create modal with current image388 const modal = document.createElement('div');389 modal.setAttribute('role', 'dialog');390 modal.setAttribute('aria-modal', 'true');391 modal.setAttribute('aria-labelledby', 'modal-title');392 modal.className = 'image-modal';393394 modal.innerHTML = `395 <div class="modal-content">396 <button type="button"397 class="close-button"398 aria-label="Close modal"399 onclick="closeImageModal()">400 ×401 </button>402 <h2 id="modal-title" class="visually-hidden">Product Image</h2>403 <img src="${currentImage.src}"404 alt="${currentImage.alt}"405 class="modal-image">406 </div>407 `;408409 document.body.appendChild(modal);410411 // Focus management412 const closeButton = modal.querySelector('.close-button');413 closeButton.focus();414415 // Trap focus within modal416 trapFocus(modal);417 }418419 function closeImageModal() {420 const modal = document.querySelector('.image-modal');421 if (modal) {422 // Restore focus to the zoom button423 const zoomButton = document.querySelector('.zoom-button');424 if (zoomButton) {425 zoomButton.focus();426 }427 modal.remove();428 }429 }430431 // Infinite loop thumbnail navigation432 function slideThumbnails(direction) {433 const thumbnailList = document.querySelector('#thumbnails');434 const thumbnails = thumbnailList.querySelectorAll('li');435 const visibleCount = 3; // Number of visible thumbnails on mobile436 const thumbnailWidth = 68; // 60px width + 8px gap437 const currentTransform = getComputedStyle(thumbnailList).transform;438 const currentX = currentTransform === 'none' ? 0 : parseInt(currentTransform.split(',')[4]) || 0;439440 let newX = currentX;441442 if (direction === 'next') {443 newX = currentX - (visibleCount * thumbnailWidth);444 } else if (direction === 'prev') {445 newX = currentX + (visibleCount * thumbnailWidth);446 }447448 // Infinite loop - wrap around when reaching the end449 const totalWidth = thumbnails.length * thumbnailWidth;450 if (newX <= -totalWidth) {451 newX = 0;452 } else if (newX > 0) {453 newX = -totalWidth + (visibleCount * thumbnailWidth);454 }455456 thumbnailList.style.transform = `translateX(${newX}px)`;457 }458```459460 **6. Accessibility Testing Checklist:**461```javascript462 function testGalleryAccessibility() {463 const issues = [];464465 // Check landmark structure466 const galleryRegion = document.querySelector('[role="region"][aria-label*="Gallery"]');467 if (!galleryRegion) {468 issues.push('Missing gallery region landmark');469 }470471 // Check thumbnail button accessibility472 const thumbnailButtons = document.querySelectorAll('.thumbnail-button');473 thumbnailButtons.forEach((button, index) => {474 if (!button.getAttribute('aria-label')) {475 issues.push(`Thumbnail button ${index + 1} missing aria-label`);476 }477 if (!button.getAttribute('aria-describedby')) {478 issues.push(`Thumbnail button ${index + 1} missing aria-describedby`);479 }480 if (!button.getAttribute('aria-controls')) {481 issues.push(`Thumbnail button ${index + 1} missing aria-controls`);482 }483 });484485 // Check live region486 const liveRegion = document.querySelector('[role="status"]');487 if (!liveRegion) {488 issues.push('Missing live region for announcements');489 }490491 // Check image alt text492 const images = document.querySelectorAll('img');493 images.forEach((img, index) => {494 if (!img.alt) {495 issues.push(`Image ${index + 1} missing alt text`);496 }497 });498499 return issues;500 }501```502503 **Gallery Structure Requirements:**504505 **Landmark Structure:**506 - **role="region"**: On gallery container507 - **aria-labelledby**: References heading ID for gallery identification508 - **Heading element**: h2-h6 with unique ID for semantic structure509 - **Proper heading hierarchy**: Use h2-h6 for gallery sections510511 **Gallery Viewer:**512 - **Unique ID**: For aria-controls reference513 - **Alt text**: Descriptive alt text on main images514 - **Zoom button**: Properly labeled with aria-label and aria-haspopup="dialog"515 - **Focus management**: Maintain focus during media changes516 - **Modal focus restoration**: Return focus to zoom button when modal closes517518 **Thumbnail Navigation:**519 - **Button elements**: Use native button or role="button"520 - **Descriptive labels**: aria-label with "Load media X into gallery viewer"521 - **State indication**: aria-current="true" for active media522 - **Context information**: aria-describedby for media alt text523 - **Control reference**: aria-controls for gallery viewer524525 **Live Announcements:**526 - **role="status"**: For live region functionality (no aria-live needed)527 - **Dynamic content management**: JavaScript inserts/removes text content528 - **No aria-hidden**: Content managed through JavaScript, not ARIA attributes529 - **Timing control**: 3-second display before hiding530531 **Mobile Responsiveness:**532 - **Unified system**: Single thumbnail list for both desktop and mobile533 - **Infinite loop navigation**: Previous/next controls with seamless wrapping534 - **Smooth animations**: CSS transitions for thumbnail sliding535 - **Responsive layout**: Grid on desktop, horizontal slider on mobile536 - **Touch accessibility**: Proper touch targets and gestures537538 **Modal Integration:**539 - **Zoom functionality**: Button overlaid on gallery viewer540 - **Modal compliance**: Follow modal accessibility standards541 - **Focus management**: Proper focus trapping and restoration542 - **Close controls**: Accessible close button with proper labeling543544 **Testing and Validation:**545 - Test with screen readers (NVDA, JAWS, VoiceOver)546 - Verify landmark navigation works correctly547 - Check thumbnail button announcements548 - Test unified thumbnail system on both desktop and mobile549 - Validate infinite loop navigation functionality550 - Test smooth thumbnail sliding animations551 - Validate modal window accessibility552 - Ensure focus management works properly553 - Test with keyboard-only navigation554 - Verify responsive design across different screen sizes555 - Test thumbnail center alignment on all devices556557 **Common Mistakes to Avoid:**558 - Missing role="region" on gallery container559 - Incomplete aria-labelledby on gallery region560 - Missing heading element with unique ID for aria-labelledby561 - Missing alt text on gallery images562 - Thumbnail buttons without proper button semantics563 - Missing aria-current state management564 - Incomplete aria-describedby references565 - Missing aria-controls on thumbnail buttons566 - Live region not properly managed567 - Separate thumbnail systems for desktop and mobile (use unified system)568 - Mobile slider without infinite loop navigation569 - Zoom button without modal functionality570 - Missing focus management during media changes571 - Missing aria-haspopup="dialog" on zoom button572 - Missing focus restoration when modal closes573 - Redundant aria-live attribute on role="status" elements574 - Unnecessary aria-hidden on dynamically managed live regions575 - Missing smooth animations for thumbnail navigation576 - Incomplete responsive design implementation577578metadata:579 priority: high580 version: 1.0581</rule>582description:583globs:584alwaysApply: false585---586
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
