diff --git a/cypress/integration/modules/a11y.js b/cypress/integration/modules/a11y.js index 5db0ea497..0d7bc614c 100644 --- a/cypress/integration/modules/a11y.js +++ b/cypress/integration/modules/a11y.js @@ -14,6 +14,14 @@ context('Core', () => { cy.getSliderWrapper().should('have.attr', 'aria-live', 'polite'); }); + it.only('paginationBulletMessage', () => { + cy.initSwiper({ + pagination: true, + a11y: { paginationBulletMessage: 'Slide to {{index}}' }, + }); + cy.getPaginationBullet(1).should('have.attr', 'Slide to', '2'); + }); + it('should add aria-role-description="slide" to swiper-slide', () => { cy.initSwiper({ a11y: { itemRoleDescriptionMessage: 'test' }, @@ -21,6 +29,15 @@ context('Core', () => { cy.getSlides().should('have.attr', 'aria-role-description', 'test'); }); + it('should add aria-label="1 of 10" to swiper-slide', () => { + cy.initSwiper({ + a11y: { slideLabelMessage: '{{index}} of {{slidesLength}}' }, + }); + cy.getSlide(0).should('have.attr', 'aria-label', '1 of 10'); + cy.getSlide(4).should('have.attr', 'aria-label', '5 of 10'); + cy.getSlide(9).should('have.attr', 'aria-label', '10 of 10'); + }); + it('should add aria-role-description="slide" to swiper-container', () => { cy.initSwiper({ a11y: { containerRoleDescriptionMessage: 'test' }, diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 7ea4d262d..618b23e75 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -30,6 +30,7 @@ Cypress.Commands.add('getSliderContainer', { prevSubject: 'optional' }, () => { Cypress.Commands.add('getSlide', { prevSubject: 'optional' }, (subject, slideIndex) => { return cy.get(`.swiper-slide:nth-child(${slideIndex + 1})`); }); + Cypress.Commands.add('getSlideContains', { prevSubject: 'optional' }, (subject, content) => { cy.get('.swiper-container').contains(content); }); @@ -40,6 +41,10 @@ Cypress.Commands.add('swiperPage', { prevSubject: 'optional' }, () => { return cy.visit('cypress/test.html'); }); +Cypress.Commands.add('getPaginationBullet', { prevSubject: 'optional' }, (subject, bulletIndex) => { + return cy.get(`.swiper-pagination-bullet:nth-child(${bulletIndex + 1})`); +}); + Cypress.Commands.add( 'initSwiper', { prevSubject: 'optional' }, diff --git a/src/components/a11y/a11y.js b/src/components/a11y/a11y.js index 801bdc0ae..8833cf3f3 100644 --- a/src/components/a11y/a11y.js +++ b/src/components/a11y/a11y.js @@ -167,7 +167,10 @@ const A11y = { swiper.a11y.addElRole($(swiper.slides), 'group'); swiper.slides.each((slideEl) => { const $slideEl = $(slideEl); - swiper.a11y.addElLabel($slideEl, `${$slideEl.index() + 1} / ${swiper.slides.length}`); + const ariaLabelMessage = params.slideLabelMessage + .replace(/\{\{index\}\}/, $slideEl.index() + 1) + .replace(/\{\{slidesLength\}\}/, swiper.slides.length); + swiper.a11y.addElLabel($slideEl, ariaLabelMessage); }); // Navigation @@ -259,6 +262,7 @@ export default { firstSlideMessage: 'This is the first slide', lastSlideMessage: 'This is the last slide', paginationBulletMessage: 'Go to slide {{index}}', + slideLabelMessage: '{{index}} / {{slidesLength}}', containerMessage: null, containerRoleDescriptionMessage: null, itemRoleDescriptionMessage: null, diff --git a/src/types/components/a11y.d.ts b/src/types/components/a11y.d.ts index c73cabde3..d85f3dfc4 100644 --- a/src/types/components/a11y.d.ts +++ b/src/types/components/a11y.d.ts @@ -72,4 +72,11 @@ export interface A11yOptions { * @default null */ itemRoleDescriptionMessage?: string | null; + + /** + * Message for screen readers describing the label of slide element + * + * @default '{{index}} / {{slidesLength}}' + */ + slideLabelMessage?: string; }