Carousels are the most complained-about component in web development — and also the most downloaded. Every marketing homepage, product gallery, and testimonial row needs one, and the gap between a janky, keyboard-unfriendly slider and a buttery one is exactly the gap between Swiper (41,881 stars), Embla Carousel (8,389 stars), and Splide (5,361 stars). In 2026 the choice is less about “which can scroll horizontally” and more about bundle size, accessibility defaults, framework integration, and how much control you want over the physics of the motion itself.

TL;DR — Quick Verdict

  • Pick Swiper if you want the most battle-tested carousel on the web with 90+ built-in modules — navigation, pagination, autoplay, virtual slides, effects — and don’t mind a heavier bundle.
  • Pick Embla Carousel if you are building a custom, design-driven slider with fluid motion and need full control: it is a headless engine (about 3-5 KB) that does not dictate markup.
  • Pick Splide if you want an accessible, dependency-free, no-config carousel that just works — its two-year commit silence is a sign of stability, not abandonment.

Feature Comparison Table

DimensionSwiperEmbla CarouselSplide
GitHub stars (2026-08-19)41,8818,3895,361
Last push2026-08-062026-08-112024-07-08
Bundle size (core)~30 KB gzip (with modules)~3-5 KB gzip~11 KB min+gzip
DependenciesZero (core)ZeroZero
Framework adaptersReact, Vue, Svelte, Angular, SolidReact, Vanilla (community: Vue/Svelte)React, Vue (official)
Touch/swipeExcellentExcellent (physics engine)Excellent
AccessibilityARIA + keyboard (manual config)Headless — you build itBest defaults out of the box
Effects (fade/cube/coverflow)ManyFade only (manual)Fade + loop
Virtual slides (100k+ items)Built-in moduleManualNo
Auto-playModulePluginBuilt-in
LicenseMITMITMIT

Use Case Decision Matrix

Use CaseRecommendationWhy
Marketing homepage, product gallerySwiperEverything works out of the box; effects + breakpoints + lazy loading
Design-system carousel with custom motionEmblaPhysics-based scrolling and zero markup assumptions
Accessibility-audited government/enterprise sitesSplideBest ARIA/role/keyboard defaults, tiny API surface
React app with 3-5 slidesEmblaSmallest React footprint, no CSS injected
Complex “showcase” carousels (coverflow, cube)SwiperEffect modules no other library matches
Long-running project, no maintenance budgetSplide or EmblaSplide is frozen-stable; Embla is minimal enough to trust

Swiper — The 900-Pound Gorilla That Earned It

Swiper is the most popular mobile touch slider on the web, and its GitHub description says exactly that: “Most modern mobile touch slider with hardware accelerated transitions.” With 41,881 stars and a release cadence measured in weeks (last push 2026-08-06), it is the safest long-term bet of the three — and also the biggest.

Vanilla setup with modules:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import Swiper from 'swiper';
import 'swiper/css';
import { Navigation, Pagination, Autoplay } from 'swiper/modules';

const swiper = new Swiper('.swiper', {
  modules: [Navigation, Pagination, Autoplay],
  loop: true,
  navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' },
  pagination: { el: '.swiper-pagination', clickable: true },
  autoplay: { delay: 3000, disableOnInteraction: false },
});

React version:

1
2
3
4
5
6
7
8
9
import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation, Pagination } from 'swiper/modules';
import 'swiper/css';

<Swiper modules={[Navigation, Pagination]} navigation pagination={{ clickable: true }} loop>
  <SwiperSlide>Slide 1</SwiperSlide>
  <SwiperSlide>Slide 2</SwiperSlide>
  <SwiperSlide>Slide 3</SwiperSlide>
</Swiper>

Swiper’s superpower is coverage: virtual slides for 100,000-item lists, lazy loading images, RTL support, keyboard navigation, thumbs-gallery syncing, and effect modules (fade, cube, coverflow, flip) that no competitor replicates. The price is complexity: the core plus common modules lands around 25-40 KB gzipped, and its CSS files ship opinionated styles you must override. If your team fights its defaults more than it uses them, you are paying for features you do not need.

Embla’s pitch is “a lightweight carousel library with fluid motion and great swipe precision” — and at ~3-5 KB gzipped with zero dependencies, it is the leanest serious option. Embla does not ship markup, classes, or CSS. You provide the DOM (typically a scroll container with flex children) and the library drives the scroll physics, snapping, and momentum. The official React hook is the cleanest carousel API in the ecosystem:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import useEmblaCarousel from 'embla-carousel-react';

function Carousel() {
  const [emblaRef] = useEmblaCarousel({ loop: true, align: 'center' });

  return (
    <div className="overflow-hidden" ref={emblaRef}>
      <div className="flex">
        <div className="min-w-0 flex-[0_0_100%]">Slide 1</div>
        <div className="min-w-0 flex-[0_0_100%]">Slide 2</div>
        <div className="min-w-0 flex-[0_0_100%]">Slide 3</div>
      </div>
    </div>
  );
}

Embla Carousel fluid motion

Because Embla is headless, you own the ARIA roles, buttons, dots, and keyboard handling — which is either freedom or a trap. The maintainer (davidjerleke) ships excellent official examples for accessibility, RTL, autoplay, and drag-free variants, but you must copy them into your codebase. Embla also exposes low-level events and APIs (embla.scrollTo(), embla.on('select', ...)) that make advanced gestures (drag-to-zoom, snap-to-grid) genuinely achievable. Its API has been stable across recent majors, but note that it moved fast between v6 and v8 — pin your version.

Splide — The Accessible, Zero-Drama Default

Splide is a TypeScript carousel with “no dependencies, no Lighthouse errors” (official description), and it has been in maintenance-stable mode since mid-2024 — the last push was July 2024, two years before this article. For a carousel library, that silence is mostly good news: v4 has no known CVEs, no framework churn to chase, and the API surface is tiny enough to trust blind.

Markup and mount:

1
2
3
4
5
6
7
8
<div class="splide" aria-label="Product gallery">
  <div class="splide__track">
    <ul class="splide__list">
      <li class="splide__slide"><img src="product-1.jpg" alt="Product 1"></li>
      <li class="splide__slide"><img src="product-2.jpg" alt="Product 2"></li>
    </ul>
  </div>
</div>
1
2
3
4
5
6
7
8
import Splide from '@splidejs/splide';

new Splide('.splide', {
  type: 'loop',
  perPage: 3,
  gap: '1rem',
  autoplay: true,
}).mount();

Splide’s real differentiator is accessibility by default: correct role="region"/aria-roledescription semantics, keyboard arrows, and aria-live handling are baked in, which is why it passes automated audits (Lighthouse) with zero configuration. The trade-offs: no virtual slides, no fancy effects beyond fade/loop, and a smaller community — if you hit an edge case, you are on your own, since the project is not actively evolving. For the classic “show 3 cards, loop, autoplay, accessible” requirement, Splide is genuinely the least-code solution.

Pitfalls and Migration Gotchas

  • Autoplay + accessibility = lawsuits. Autoplaying carousels that cannot be paused fail WCAG 2.2.1 (Pause, Stop, Hide). Swiper’s disableOnInteraction and Splide’s autoplay both need explicit pause-on-hover and a visible control; Embla leaves it entirely to you. If your carousel auto-advances, ship a pause button and honor prefers-reduced-motion — with any library.
  • Don’t nest carousels. A carousel inside a carousel breaks drag gestures on touch devices (horizontal scroll ambiguity). Flatten the layout or lock the outer carousel while interacting with the inner one — there is no library-level fix.
  • Images are the real performance bottleneck. Every carousel library lazy-loads differently: Swiper has a lazy module, Splide lazy-loads data-splide-lazy sources, Embla does nothing — you must use loading="lazy" or IntersectionObserver yourself. For heavy galleries, see our JavaScript virtual scrolling guide before rendering 500 slides.
  • RTL and dynamic resizes. Swiper handles RTL and container resizing robustly out of the box; Embla needs watchResize and careful direction handling in v8; Splide’s RTL support exists but is less polished. If you ship Arabic/Hebrew, test all three in your real layout before committing.
  • Framework version churn. Swiper 11+ and Embla v8 both reworked options between majors. If you upgrade, read the changelog — slidesPerView → breakpoints syntax, Embla’s loop semantics, and Splide’s type values all changed at various points. Pin versions in CI.
  • Frozen dependencies beat abandoned ones. A stale repo is not automatically dead: Splide has shipped zero releases in two years because it does not need them. Check issue responsiveness and whether the maintainer still triages PRs — a responsive-but-slow project is healthier than a fast one with unmerged security fixes.
  • Don’t hand-roll a carousel “to save 5 KB.” Horizontal scrolling, snap points, momentum, and touch/focus coordination are notoriously fiddly — the classic failure mode is a custom slider that passes QA on desktop and feels broken on a phone. If you need less than Embla’s feature set, use plain CSS scroll-snap — see how interaction primitives compare in our drag and drop library guide for the same build-vs-buy reasoning.

Performance Notes and Bundle Budgets

Measured with gzip on a default setup: Swiper core + navigation + pagination + autoplay ≈ 28-35 KB; Splide full ≈ 11 KB; Embla core ≈ 3-5 KB. On a marketing page with an aggressive Core Web Vitals budget, Embla or Splide are the responsible choices and leave room for the rest of the bundle. On a product-heavy site where development speed matters more than bytes, Swiper’s feature coverage wins — and remember that carousel images, not the library, will dominate your LCP in practice. For motion polish around sliders, pair your choice with a library from our JavaScript animation comparison rather than chasing it inside the carousel itself.

FAQ

Swiper is the most popular by a wide margin, with 41,881 GitHub stars as of 2026-08-19, followed by Embla Carousel (8,389 stars) and Splide (5,361 stars). Swiper also leads in downloads and is the default choice in most CMS themes and website builders.

It depends on your priorities. Embla is dramatically smaller (~3-5 KB vs 30+ KB), has no opinionated CSS, and gives you complete control over markup and motion. Swiper provides far more built-in features (effects, virtual slides, lazy loading, thumbs) and requires less custom code. Embla wins on control and size; Swiper wins on coverage and speed of development.

Is Splide abandoned?

No — Splide v4 is in maintenance-stable mode. The last commit was July 2024, but the project has no open critical issues, no known CVEs, and its small API surface rarely needs changes. For teams that want a stable, accessible carousel without churn, this is a feature. Teams needing new features should choose Swiper or Embla instead.

Splide has the best accessibility defaults out of the box (ARIA roles, keyboard navigation, reduced-motion handling). Embla is headless, so you implement ARIA yourself following the official examples. Swiper includes ARIA support but requires deliberate configuration for full WCAG compliance.

Swiper ships official adapters for React, Vue, Svelte, Angular, and Solid. Embla has an official React adapter plus community adapters. Splide provides official React and Vue wrappers. All three work in vanilla JavaScript.

Do these libraries support RTL and touch devices?

All three support touch/swipe and RTL. Swiper has the most mature RTL and responsive breakpoint support, Embla handles RTL with the direction option (verify with watchResize), and Splide supports RTL with slightly less polish. Always test your real layout on a phone before shipping.


💰 想测试你的市场判断力?我用 Polymarket 做预测市场交易——这是全球最大的预测市场平台,从大选结果到技术监管时间线,什么都可以押注。和赌博不同,这是真正的信息市场:你懂的信息越多,胜率越高。我靠预测技术相关事件的走向已经赚了不少。用我的邀请链接注册:Polymarket.com