The demo:

See the Pen Swiper-Slider: Scroll, Drag, and Click to Navigate by AT Studio (@AtStudio) on CodePen.

HTML

<swiper-slider>
  <article>
    <ul class="slider">
      <li>
        <figure>
          <blockquote>
            <p>"This isn't just about staying relevant in a rapidly evolving industry; it's about leading the way."
            </p>
          </blockquote>
          <figcaption>
            <p>Kenny Demaio</p>
            <p>SVP of Operations</p>
            <a href="">See the story
              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" fill="none">
                <path d="M3.333 8.167h9.334m0 0L10 10.833m2.667-2.666L10 5.5" stroke="#fff" stroke-width="1.5"
                  stroke-linecap="round" stroke-linejoin="round">
              </svg>
            </a>
          </figcaption>
        </figure>
      </li>
      <li>
        <figure>
          <blockquote>
            <p>"We can be way more creative in what we're putting out into the world"
            </p>
          </blockquote>
          <figcaption>
            <p>Rudolf Lewis</p>
            <p>SVP of Operations</p>
            <a href="">See the story
              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" fill="none">
                <path d="M3.333 8.167h9.334m0 0L10 10.833m2.667-2.666L10 5.5" stroke="#fff" stroke-width="1.5"
                  stroke-linecap="round" stroke-linejoin="round">
              </svg>
            </a>
          </figcaption>
        </figure>
      </li>
      <li>
        <figure>
          <blockquote>
            <p>"Crafter's brand and voice tools help our teams work even better together. We're able to align faster and collaborate more effectively."
            </p>
          </blockquote>
          <figcaption>
            <p>John Bean</p>
            <p>Sr. Manager, Campaign Strategy</p>
            <a href="">See the story
              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" fill="none">
                <path d="M3.333 8.167h9.334m0 0L10 10.833m2.667-2.666L10 5.5" stroke="#fff" stroke-width="1.5"
                  stroke-linecap="round" stroke-linejoin="round">
              </svg>
            </a>
          </figcaption>
        </figure>
      </li>
    </ul>
    <ul class="img_container">
      <li>
        <img src="https://atstudioadmin.netlify.app/uploads/kenny.avif" alt="Photo of Kenny Demaio">
      </li>
      <li>
        <img src="https://atstudioadmin.netlify.app/uploads/rudolf.avif" alt="Photo of Rudolf Lewis">
      </li>
      <li>
        <img src="https://atstudioadmin.netlify.app/uploads/john.avif" alt="Photo of John Bean">
      </li>
    </ul>
    <menu class="pagination">
      <li>
        <button active></button>
      </li>
      <li>
        <button></button>
      </li>
      <li>
        <button></button>
      </li>
    </menu>
  </article>
</swiper-slider>

Testimonial sliders are a familiar design pattern. Each slide features a quote, the person who said it, and pagination buttons so users can flip through the slides.

Why swiper-slider wraps article?

The <swiper-slider> wrapper is there to leverage @container-query. Here’s the catch: you can’t apply @container-query styles directly to the element defined as the container. So, I added this extra layer to style the <article> responsively.

Custom element vs. div

Instead of using <div class="swiper-slider">, I went with a custom element, <swiper-slider>. Both are generic containers and behave the same for screen readers without ARIA attributes. But <swiper-slider> is cleaner and more intuitive for other developers. Plus, when styling, a type selector (like swiper-slider) has lower specificity than a class selector (.swiper-slider), which keeps things flexible.

Why article element?

The <article> element represents a complete, or self-contained, composition in a document, page, application, or site and that is, in principle, independently distributable or reusable, e.g. in syndication. The swiper slider is a resuable component, therefore, the entire component is a good candidate to be wrapped in an <article> element.

Structuring the content

nside the slider, I prioritized the quote, since that is the most important information for the user who is checking out the testimonial section, follwed by the image, and finally the pagination for the user to switch between slides.

Quoting right

John Rhea has a detailed article about Quoting in HTML. I wrapped the quote in <blockquote>, tucked the person’s name and job title in <figcaption> (since they’re not part of the quote itself), and used <figure> to tie the quote to its attribution. One thing to note: I avoided <cite> for the name and title because it’s meant for titles of works (like books or articles), not people. The HTML spec has a great example of this with <blockquote> and <figure> - notice how “Wonder and Skepticism” uses , but “Carl Sagan” doesn’t.

Image placement

Ideally, the images would live inside <figure> since they’re part of the self-contained unit. But for this design, I had to move them into a separate container. If you’ve got a clever workaround, I’d love to hear it! Drop me an email or ping me on Bluesky at @alexdevvv.bsky.social.

ul vs. menu

What's the difference?

According to MDN

The <menu> and <ul> elements both represent an unordered list of items. The key difference is that <ul> primarily contains items for display, while <menu> represents a toolbar containing commands that the user can perform or activate.

The HTML specs:

The menu element is simply a semantic alternative to ul to express an unordered list of commands (a "toolbar").

<ul> is for unordered lists of items meant for display, while <menu> is for interactive toolbars with commands. That’s why I used <menu> for the pagination buttons — they’re interactive controls. For the slider content and image list, I stuck with <ul> since they’re just displaying items.

That wraps up the HTML part of the slider. In the next post, we’ll tackle the CSS. Stay tuned!