Avara UI

Carousels

Algorize UI ships its own Carousel set for the common cases. These two libraries are for when you need something it does not do: Embla when you want the physics and none of the markup, Swiper when you want effects, thumbnails and a11y wiring out of the box.

Embla

Embla ships no markup and no CSS of its own — it hands back a ref and an API object. The viewport, the track, the arrows and the dots are all yours, which means the controls here are ordinary Buttons and each slide is an ordinary Card. Nothing is being restyled or overridden.

Drag, swipe, arrows and dots. Embla positions the track; every pixel you can see belongs to the design system.

Theviewport
takes overflow-hidden and the ref; the track directly inside it is a flex row. Embla translates that row — it does not create it.
basis
on each slide is how many are visible: basis-[80%] on mobile through lg:basis-[32%] for three. Keep min-w-0 shrink-0 grow-0 or flex will resize the slides instead.
emblaApi
is undefined on the first render. Guard it, and subscribe to select and reInit (here through useSyncExternalStore) to drive the dots.
loop{true}
clones slides internally, so read the active index from selectedScrollSnap() rather than tracking it yourself.

Installation

npm install embla-carousel-react
This example also uses these Algorize UI components — install whichever your project does not already have:
npx shadcn@latest add @algorize-ui/card @algorize-ui/ui-badge @algorize-ui/button

Swiper

Swiper brings its own CSS, which is exactly why the slides stay yours: import only the modules you use, then let Card own everything inside the slide. Its own chrome — arrows and bullets — is repointed at the tokens through the CSS variables it already reads, so there is no stylesheet to override.

Coverflow testimonials

Autoplay, coverflow depth, clickable pagination and keyboard-reachable arrows — none of which you write. The card inside each slide is unchanged.

Importmodules
and their CSS in pairs. EffectCoverflow without swiper/css/effect-coverflow renders a plain, un-transformed row.
--swiper-navigation-color
and --swiper-pagination-color are the supported way to theme the chrome. Overriding .swiper-button-next with a utility class loses to Swiper's own stylesheet.
slidesPerView"auto"
hands slide width back to you — hence !w-[280px] on the slide. Fixed widths are what make a coverflow read as a deck.
items-stretch
on the wrapper plus h-auto on the slide is what gives the cards one shared height; without it each slide is only as tall as its own quote.

Installation

npm install swiper
This example also uses these Algorize UI components — install whichever your project does not already have:
npx shadcn@latest add @algorize-ui/card @algorize-ui/ui-badge

Which one

EmblaSwiper
Bundle~5 kB~40 kB+ per module set
MarkupYoursYours, inside its wrapper
CSSNoneShips its own
Effects (coverflow, cube, cards)Build itBuilt in
Thumbnails, virtual slides, zoomBuild itModules
Autoplay, a11yPluginsModules
Embla is the better default when the carousel is a row of your own cards: it is tiny, and there is nothing to fight. Swiper earns its size when you want the effects and the extras rather than reimplementing them.
Both are also worth weighing against the built-in Carousel components, which cover image, hero, thumbnail and radial layouts with no third-party dependency at all.