Swiper Multi-Row Grid Carousel — Free JS Snippet

Swiper Multi-Row Grid Carousel · Carousels · Plain HTML, CSS & JS · Live preview

What's included

Features

Two-row grid using the grid module (rows and fill)
slidesPerGroup so each swipe moves one full page
Responsive column count through breakpoints
Explicit container height and slide height maths that accounts for the gap
Custom previous/next buttons with disabled states
Progress-bar pagination instead of dots
Keyboard control, a11y labels and focusable tile links
Gradient and emoji tiles, no images required

About this UI Snippet

Swiper Multi-Row Grid Carousel — HTML, CSS & JavaScript

Screenshot of the Swiper Multi-Row Grid Carousel snippet rendered live

A single row of cards is the default shape of a carousel, but category pickers, app launchers and icon grids want more than one row: sixteen tiles arranged two-by-eight scroll sideways, showing many options at once without turning into a long page. Swiper handles this with its grid module, which arranges slides into a fixed number of rows and then scrolls the whole grid horizontally, so a multi-row carousel is a single option rather than nested sliders.

grid: { rows: 2, fill: 'row' } is the key setting. rows sets the number of rows, and fill decides the reading order: 'row' fills left to right then moves down, which matches how people read a grid, while 'column' fills top to bottom, which keeps related tiles stacked. Two things must be set up around it or the grid renders wrongly, and both trip people up. First, the container needs a definite height, because rows share it; without one the slides collapse or overlap. Second, slides need a height that is a share of the container — here calc((100% - 16px) / 2), which is half the height minus half the gap — so each row's tiles exactly fit. The gap between rows comes from spaceBetween, so the calculation has to subtract it.

Paging needs consideration too. By default Swiper advances one slide at a time, which in a grid moves the layout by a single column and feels fussy. slidesPerGroup makes each swipe or button press move a whole page, and it should equal slidesPerView — 2, 3 or 4 columns depending on width, set through breakpoints — so the pages align cleanly. Watch that the number of slides divides nicely by rows and columns, or the last page will have gaps.

The controls are separate elements rather than defaults: custom previous and next buttons wired through the navigation module, with a disabledClass so they dim at either end, and a progress-bar pagination that shows how far along the grid you are — more useful than dots for a long list. The tiles are real links with visible focus outlines, keyboard control is enabled, and the a11y module labels the controls. Categories use gradients and emoji so no images are required.

Step by step

How to Use

  1. 1
    Swipe a pageDrag the grid sideways. It moves a whole page of tiles at once rather than one column.
  2. 2
    Use the buttonsPress the arrow buttons. They dim when you reach the first or last page.
  3. 3
    Read the progress barThe bar underneath fills as you move through the grid.
  4. 4
    Resize the frameWiden or narrow the preview to see the column count change from 2 to 3 to 4.
  5. 5
    Tab through tilesUse Tab to focus tiles and see the visible focus outline.

Real-world uses

Common Use Cases

🗂️
Category and department pickers
Offer many categories at once in a two-row sideways grid, with slidesPerGroup moving one full page per swipe.
📱
App-style launchers
Present app-style shortcuts as swipeable pages of icons in a launcher, with responsive column counts defined through Swiper breakpoints.
🧩
Template galleries
Browse a large set of templates or widgets, with custom previous and next buttons and a progress bar showing position.
🔄
Coverflow comparison
Compare with the Swiper coverflow product carousel when a single focused item matters more than many options at once.
🎓
Grid layout in sliders
See how container height and slide height maths must account for the gap when using Swiper's grid module.

Got questions?

Frequently Asked Questions

Use grid: { rows: 2 }, give the container a fixed height, and set each slide's height to its share of that height.

fill: "row" places slides left to right then down, while fill: "column" places them top to bottom then across.

slidesPerGroup defaults to 1. Set it equal to slidesPerView so each swipe moves a full page.

Grid mode needs a definite container height and slide heights that subtract the gap between rows.

Use breakpoints to set slidesPerView and slidesPerGroup for each width.

Set pagination: { type: "progressbar" } and style the .swiper-pagination-progressbar-fill element.

Yes. Use the JSX, Vue, Angular or Tailwind export buttons on this page to convert the markup and styles. The behaviour comes from Swiper, so in a framework project install it with npm install swiper (its React and Vue components take the same options) instead of the CDN tag, use the Swiper and SwiperSlide components, or create it in useEffect / onMounted / ngAfterViewInit, and release it with destroy() when the component unmounts.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Ask an AI assistant like Claude to make the row count responsive, add category filters that rebuild the grid, or show a badge on tiles with new items.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a multi-row grid carousel with Swiper 11 loaded from a CDN (bundle script and CSS).

Requirements:
- Render sixteen category tiles (gradient, emoji, name, item count) and use grid: { rows: 2, fill: 'row' } with spaceBetween 16, a fixed container height and slide height calc((100% - 16px) / 2).
- Set slidesPerView and slidesPerGroup to 2, with breakpoints raising both to 3 at 480px and 4 at 640px.
- Wire custom prev/next buttons via navigation with a disabledClass, and a progressbar pagination styled with .swiper-pagination-progressbar-fill.
- Enable keyboard and a11y, make tiles focusable links with visible focus outlines.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<div class="mg-wrap">
  <div class="mg-head">
    <h3>Browse categories</h3>
    <div class="mg-nav">
      <button type="button" id="mgPrev" aria-label="Previous page">&#8249;</button>
      <button type="button" id="mgNext" aria-label="Next page">&#8250;</button>
    </div>
  </div>
  <div class="swiper mg-swiper" id="mgSwiper">
    <div class="swiper-wrapper" id="mgSlides"></div>
  </div>
  <div class="mg-progress"><div class="swiper-pagination" id="mgPag"></div></div>
</div>