Kodza

Carousel

A native scroll-snap carousel that works before the script loads. Then: page buttons, a rolling count, a progress bar or dots, and mouse drag with a throw. Never steals the wheel.

Media No dependencies carouselsliderscroll-snapdragproductstestimonials Added Oct 2026
/anim/carousel/ Fullscreen

With your AI

Just ask.

Say it to your AI. It gets the exact code below, not its best guess, and knows where it goes.

Add the Kodza Carousel to my page.

Not plugged in yet?
claude mcp add -t http kodza https://kodza.dev/api/mcp
Also in Codex, Cursor and VS Code.
kodza-carousel.html
<section class="kodza-carousel" aria-roledescription="carousel" aria-label="New prints">
  <div class="kodza-carousel__head">
    <h2 class="kodza-carousel__title">New prints</h2>
    <div class="kodza-carousel__controls">
      <span class="kodza-carousel__count" aria-hidden="true"></span>
      <button class="kodza-carousel__prev" type="button" aria-label="Previous slides">
        <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M13 8H3M7 4 3 8l4 4" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
      </button>
      <button class="kodza-carousel__next" type="button" aria-label="Next slides">
        <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 8h10M9 4l4 4-4 4" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
      </button>
    </div>
  </div>
  <div class="kodza-carousel__viewport" tabindex="0">
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <a class="kodza-carousel__card" href="#">
        <span class="kodza-carousel__media"><img src="https://kodza.dev/media/kz-arch-1400.webp" width="1400" height="1400" alt="" loading="lazy" decoding="async"></span>
        <span class="kodza-carousel__body">
          <span class="kodza-carousel__name">The Arch</span>
          <span class="kodza-carousel__price">€48</span>
          <span class="kodza-carousel__text">One way in. No side doors.</span>
        </span>
      </a>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <a class="kodza-carousel__card" href="#">
        <span class="kodza-carousel__media"><img src="https://kodza.dev/media/kz-columns-1400.webp" width="1120" height="1400" alt="" loading="lazy" decoding="async"></span>
        <span class="kodza-carousel__body">
          <span class="kodza-carousel__name">Seven Columns</span>
          <span class="kodza-carousel__price">€56</span>
          <span class="kodza-carousel__text">A grid, no framework.</span>
        </span>
      </a>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <a class="kodza-carousel__card" href="#">
        <span class="kodza-carousel__media"><img src="https://kodza.dev/media/kz-float-1400.webp" width="1400" height="933" alt="" loading="lazy" decoding="async"></span>
        <span class="kodza-carousel__body">
          <span class="kodza-carousel__name">Float</span>
          <span class="kodza-carousel__price">€42</span>
          <span class="kodza-carousel__text">Out of the flow, on purpose.</span>
        </span>
      </a>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <a class="kodza-carousel__card" href="#">
        <span class="kodza-carousel__media"><img src="https://kodza.dev/media/kz-steps-1400.webp" width="1400" height="933" alt="" loading="lazy" decoding="async"></span>
        <span class="kodza-carousel__body">
          <span class="kodza-carousel__name">Stairs to Prod</span>
          <span class="kodza-carousel__price">€64</span>
          <span class="kodza-carousel__text">Never deployed on a Friday.</span>
        </span>
      </a>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <a class="kodza-carousel__card" href="#">
        <span class="kodza-carousel__media"><img src="https://kodza.dev/media/kz-stack-1400.webp" width="1400" height="1050" alt="" loading="lazy" decoding="async"></span>
        <span class="kodza-carousel__body">
          <span class="kodza-carousel__name">The Stack</span>
          <span class="kodza-carousel__price">€52</span>
          <span class="kodza-carousel__text">z-index: 9999, still behind.</span>
        </span>
      </a>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <a class="kodza-carousel__card" href="#">
        <span class="kodza-carousel__media"><img src="https://kodza.dev/media/kz-block-1400.webp" width="1120" height="1400" alt="" loading="lazy" decoding="async"></span>
        <span class="kodza-carousel__body">
          <span class="kodza-carousel__name">Block</span>
          <span class="kodza-carousel__price">€39</span>
          <span class="kodza-carousel__text">display: block. Done. Ship it.</span>
        </span>
      </a>
    </div>
  </div>
  <div class="kodza-carousel__progress" aria-hidden="true"><span class="kodza-carousel__thumb"></span></div>
</section>

<section class="kodza-carousel kodza-carousel--quotes" aria-roledescription="carousel" aria-label="What developers say">
  <div class="kodza-carousel__viewport" tabindex="0">
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <figure class="kodza-carousel__quote">
        <blockquote class="kodza-carousel__says">Finally a carousel that doesn’t hijack my scroll wheel. I scrolled past it just to feel something.</blockquote>
        <figcaption><span class="kodza-carousel__avatar" aria-hidden="true">MK</span><span class="kodza-carousel__who"><b>Mira K.</b> Frontend, at an agency</span></figcaption>
      </figure>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <figure class="kodza-carousel__quote">
        <blockquote class="kodza-carousel__says">No npm install. No peer dependency drama. I pasted it into WordPress and went to lunch.</blockquote>
        <figcaption><span class="kodza-carousel__avatar" aria-hidden="true">TB</span><span class="kodza-carousel__who"><b>Theo B.</b> WordPress, since 4.9</span></figcaption>
      </figure>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <figure class="kodza-carousel__quote">
        <blockquote class="kodza-carousel__says">I removed 42 kB of slider plugin and nobody noticed. Except Lighthouse, who sent flowers.</blockquote>
        <figcaption><span class="kodza-carousel__avatar" aria-hidden="true">SR</span><span class="kodza-carousel__who"><b>Sam R.</b> Freelance, Lyon</span></figcaption>
      </figure>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <figure class="kodza-carousel__quote">
        <blockquote class="kodza-carousel__says">Keyboard, screen reader, reduced motion. The accessibility audit came back boring. Boring is good.</blockquote>
        <figcaption><span class="kodza-carousel__avatar" aria-hidden="true">LV</span><span class="kodza-carousel__who"><b>Lena V.</b> Accessibility lead</span></figcaption>
      </figure>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <figure class="kodza-carousel__quote">
        <blockquote class="kodza-carousel__says">Flicked it with the mouse and it landed on a slide. Like a cat. A well-behaved, snap-aligned cat.</blockquote>
        <figcaption><span class="kodza-carousel__avatar" aria-hidden="true">YA</span><span class="kodza-carousel__who"><b>Yusuf A.</b> Design engineer</span></figcaption>
      </figure>
    </div>
    <div class="kodza-carousel__slide" role="group" aria-roledescription="slide">
      <figure class="kodza-carousel__quote">
        <blockquote class="kodza-carousel__says">It worked on my machine. Then it worked on theirs. I’m still processing this.</blockquote>
        <figcaption><span class="kodza-carousel__avatar" aria-hidden="true">ID</span><span class="kodza-carousel__who"><b>Ines D.</b> CTO, team of four</span></figcaption>
      </figure>
    </div>
  </div>
  <div class="kodza-carousel__dots"></div>
</section>

Checked

Checked before you paste.

Robots poked at it before you did. Every component goes through the same checks, and again each time it changes.

What ranLast run
Accessibilityaxe-core 4.10.2: the WCAG 2.1 A and AA rules, plus best practices. 0 issues
KeyboardThe Tab key gets there, and the focus ring shows when it does. Passed
Reduced motionTurn on reduced motion and what moved just appears. Nothing loops. Passed
Light and darkThe same checks on both themes, contrast included. Passed
WordPressPasted into Twenty Twenty-Five, Twenty Twenty-One, Astra, Blocksy, GeneratePress, Hello Elementor, Kadence and OceanWP. Nothing to flag. 8 / 8 themes
Robots checked this. A human with VoiceOver hasn't yet.
KeyboardPress them in the preview
On the slides row
  • Next or previous slide→/←
  • First or last slideHome/End

More like this

More in Media