testimonialSlider.html
<div class="slider container -withCallout">
  <svg class="slider__calloutIcon icon accent-primary" role="presentation">
    <use href="/main-icons-sprite.svg#quote" />
  </svg>
  <div class="slider__callout">
    <span id="testimonial-slider-heading" class="h3"> Don’t take our word for it, read some of our thoughtful testimonials and decide for yourself. </span>
  </div>
  <div class="slider__content">
    <p-slider slides-per-view="auto" space-between="32" navigation="true" pagination-clickable="true" loop="true" aria-labelledby="testimonial-slider-heading">
      <swiper-slide loading="lazy">
        <blockquote class="testimonial">
          <p class="testimonial__content">Suspendisse ac blandit nisi, non tempor purus. Pellentesque ornare tellus molestie quam pretium aliquet. Mauris eu est at velit cursus rutrum non sit amet turpis. Phasellus mauris est, fermentum sit amet tincidunt ultricies, egestas a ante proin et eros rutrum urna sollicitudin euismod non ut sem!</p>
          <footer class="testimonial__footer">
            <div class="testimonial__citationPhotoWrapper">
              <img src="https://picsum.photos/400" alt="Placeholder photo" class="testimonial__citationPhoto" />
            </div>
            <cite class="testimonial__citation">
              Firstnamerson Lastname
              <span class="testimonial__citationTitle"> Director of Important Titles, CorporateCorp </span>
            </cite>
          </footer>
        </blockquote>
      </swiper-slide>
      <swiper-slide loading="lazy">
        <blockquote class="testimonial">
          <p class="testimonial__content">Lorem ipsum dolor sit amet consectetur adipisicing elit. Nihil accusantium eligendi tempore placeat facere non enim expedita eum iusto delectus veniam inventore, a cumque vel? Illum ipsa in tempore minima?</p>
          <footer class="testimonial__footer">
            <div class="testimonial__citationPhotoWrapper">
              <img src="https://picsum.photos/400" alt="Placeholder photo" class="testimonial__citationPhoto" />
            </div>
            <cite class="testimonial__citation">
              Firstnamerson Lastname
              <span class="testimonial__citationTitle"> Director of Important Titles, CorporateCorp </span>
            </cite>
          </footer>
        </blockquote>
      </swiper-slide>
      <swiper-slide loading="lazy">
        <blockquote class="testimonial">
          <p class="testimonial__content">Lorem ipsum dolor sit amet consectetur adipisicing elit. Mollitia quo, maiores rerum ducimus et numquam maxime labore dolores laboriosam dolorum repudiandae consequuntur animi voluptas dignissimos reprehenderit modi non quibusdam amet.</p>
          <footer class="testimonial__footer">
            <div class="testimonial__citationPhotoWrapper">
              <img src="https://picsum.photos/400" alt="Placeholder photo" class="testimonial__citationPhoto" />
            </div>
            <cite class="testimonial__citation">
              Firstnamerson Lastname
              <span class="testimonial__citationTitle"> Director of Important Titles, CorporateCorp </span>
            </cite>
          </footer>
        </blockquote>
      </swiper-slide>
      <swiper-slide loading="lazy">
        <blockquote class="testimonial">
          <p class="testimonial__content">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Quae animi molestias non itaque reiciendis facere est suscipit consequuntur eaque ipsum explicabo, corporis nulla enim earum fuga, distinctio voluptate possimus deserunt?</p>
          <footer class="testimonial__footer">
            <div class="testimonial__citationPhotoWrapper">
              <img src="https://picsum.photos/400" alt="Placeholder photo" class="testimonial__citationPhoto" />
            </div>
            <cite class="testimonial__citation">
              Firstnamerson Lastname
              <span class="testimonial__citationTitle"> Director of Important Titles, CorporateCorp </span>
            </cite>
          </footer>
        </blockquote>
      </swiper-slide>
      <swiper-slide loading="lazy">
        <blockquote class="testimonial">
          <p class="testimonial__content">Suspendisse ac blandit nisi, non tempor purus. Pellentesque ornare tellus molestie quam pretium aliquet. Mauris eu est at velit cursus rutrum non sit amet turpis. Phasellus mauris est, fermentum sit amet tincidunt ultricies, egestas a ante proin et eros rutrum urna sollicitudin euismod non ut sem!</p>
          <footer class="testimonial__footer">
            <div class="testimonial__citationPhotoWrapper">
              <img src="https://picsum.photos/400" alt="Placeholder photo" class="testimonial__citationPhoto" />
            </div>
            <cite class="testimonial__citation">
              Firstnamerson Lastname
              <span class="testimonial__citationTitle"> Director of Important Titles, CorporateCorp </span>
            </cite>
          </footer>
        </blockquote>
      </swiper-slide>
      <swiper-slide loading="lazy">
        <blockquote class="testimonial">
          <p class="testimonial__content">Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi, exercitationem adipisci laboriosam nulla modi omnis excepturi vitae deleniti illum porro. Mollitia modi laudantium doloremque fugiat nostrum itaque quod quo error!</p>
          <footer class="testimonial__footer">
            <div class="testimonial__citationPhotoWrapper">
              <img src="https://picsum.photos/400" alt="Placeholder photo" class="testimonial__citationPhoto" />
            </div>
            <cite class="testimonial__citation">
              Firstnamerson Lastname
              <span class="testimonial__citationTitle"> Director of Important Titles, CorporateCorp </span>
            </cite>
          </footer>
        </blockquote>
      </swiper-slide>
      <swiper-slide loading="lazy">
        <blockquote class="testimonial">
          <p class="testimonial__content">Lorem ipsum dolor, sit amet consectetur adipisicing elit. Velit, obcaecati! Suscipit quidem ipsa qui sunt nihil aliquid. Alias veniam maxime, assumenda amet, totam, cupiditate sunt ab exercitationem voluptas incidunt harum.</p>
          <footer class="testimonial__footer">
            <div class="testimonial__citationPhotoWrapper">
              <img src="https://picsum.photos/400" alt="Placeholder photo" class="testimonial__citationPhoto" />
            </div>
            <cite class="testimonial__citation">
              Firstnamerson Lastname
              <span class="testimonial__citationTitle"> Director of Important Titles, CorporateCorp </span>
            </cite>
          </footer>
        </blockquote>
      </swiper-slide>
    </p-slider>
  </div>
</div>
PSlider.vue
<script setup>
import { register } from 'swiper/element/bundle'
import { ref } from 'vue'

register()

const props = defineProps({
  ariaLabel: {
    type: String,
    default: undefined,
  },
  ariaLabelledby: {
    type: String,
    default: undefined,
  },
  autoplay: {
    type: [Boolean, Object],
    default: undefined,
  },
})

const isPlaying = ref(!!props.autoplay)

let swiperInstance = null

const toggleAutoplay = () => {
  if (!swiperInstance) return

  if (isPlaying.value) {
    swiperInstance.autoplay.stop()
    swiperInstance.wrapperEl.setAttribute('aria-live', 'polite')
  } else {
    swiperInstance.autoplay.start()
    swiperInstance.wrapperEl.setAttribute('aria-live', 'off')
  }
  isPlaying.value = !isPlaying.value
}

const updateActiveBullet = (swiper) => {
  if (!swiper.pagination?.bullets) return
  swiper.pagination.bullets.forEach((bullet) => {
    bullet.setAttribute('aria-disabled', bullet.classList.contains('swiper-pagination-bullet-active') ? 'true' : 'false')
  })
}

const init = e => {
  swiperInstance = e.detail[0]

  // The following code is for slider accessibility not covered by Swiper's a11y module.
  // Please see the slider README.md or the W3C carousel pattern for more information:
  // README: ../../../styles/organisms/slider/README.md
  // W3C: https://www.w3.org/WAI/ARIA/apg/patterns/carousel/

  // Swiper has no param for aria-labelledby; set it on the inner .swiper container
  // (swiperInstance.el), matching where the a11y module applies aria-label
  if (props.ariaLabelledby) {
    swiperInstance.el.setAttribute('aria-labelledby', props.ariaLabelledby)
    swiperInstance.el.removeAttribute('aria-label')
  }

  swiperInstance.wrapperEl.setAttribute('aria-atomic', 'false')

  // Pause autoplay on user interaction (focus or intentional click) while playing.
  // Listens on both the host (slotted play button) and swiper.el (shadow DOM controls).
  // Skips the play/pause button so clicking it to resume does not immediately re-pause.
  if (props.autoplay) {
    const stopAutoplay = () => {
      if (!isPlaying.value) return
      swiperInstance.autoplay.stop()
      swiperInstance.wrapperEl.setAttribute('aria-live', 'polite')
      isPlaying.value = false
    }

    const pauseAutoplayOnFocus = (event) => {
      if (event.target.closest?.('.slider__playPause')) return
      stopAutoplay()
    }

    // Pause on click of a slide, pagination bullet, or prev/next nav button.
    const pauseAutoplayOnClick = (event) => {
      if (!event.target.closest('.swiper-slide, .swiper-pagination-bullet, .swiper-button-prev, .swiper-button-next')) return
      stopAutoplay()
    }

    e.target.addEventListener('focusin', pauseAutoplayOnFocus)
    swiperInstance.el.addEventListener('focusin', pauseAutoplayOnFocus)
    swiperInstance.el.addEventListener('click', pauseAutoplayOnClick)
  }

  if (swiperInstance.pagination?.el) {
    swiperInstance.pagination.el.setAttribute('role', 'group')
    swiperInstance.pagination.el.setAttribute('aria-label', 'Choose a slide')
  }

  // Active bullet aria-disabled per W3C carousel pattern (Swiper sets aria-current only)
  updateActiveBullet(swiperInstance)
  swiperInstance.on('slideChange', updateActiveBullet)
  swiperInstance.on('paginationUpdate', updateActiveBullet)
}
</script>
<template>
  <swiper-container
    v-bind="$attrs"
    :autoplay="autoplay"
    a11y-container-role="group"
    a11y-container-role-description-message="carousel"
    :a11y-container-message="ariaLabel"
    a11y-item-role-description-message="slide"
    @swiperafterinit="init"
  >
    <button
      v-if="autoplay"
      slot="container-start"
      class="slider__playPause button -circle"
      :aria-label="isPlaying ? 'Stop slide rotation' : 'Start slide rotation'"
      @click="toggleAutoplay"
    >
      <svg class="button__icon" aria-hidden="true">
        <use :href="isPlaying ? '/main-icons-sprite.svg#pause' : '/main-icons-sprite.svg#play'" />
      </svg>
    </button>
    <slot />
  </swiper-container>
</template>