Carousels have a bad reputation that they half deserve. The version people rightly complain about is the homepage hero slider: five auto-advancing messages where four are invisible at any moment, competing for a decision the reader has not made yet. The version that works is a horizontal rail of peers - logos, images, cases, cards - where nothing is hidden that the reader needed, and moving is the point rather than the tax.
88 public components on 21st have "carousel" in the name and 70 say "slider". Sorting them by what they are actually for, rather than by how they animate, gets you four shapes.
The rail
Cards side by side, scrolled horizontally, all of them equal. This is the shape with the fewest objections, because nothing is being hidden from you: the row obviously continues, and you can see it does.
Gallery with image cards from Shadcnblocks.com is the reference version, full-height image cards with case-study text on top. Feature Carousel by 0xUrvish is the same idea for product features, and Gallery Hover Carousel by Ruixen UI adds a hover state where the image shrinks to the top half and reveals a title and a link underneath.
The detail that makes or breaks a rail is the peek. If the next card is cut off at the viewport edge, the reader knows to scroll without being told. If every card ends flush with the container, the row looks finished and half of it never gets seen.
The marquee
Logos, testimonials, screenshots: an endless scroll with no controls, because there is nothing to decide.
Logos 3 from Shadcnblocks.com is exactly this, client logos scrolling automatically inside masked edges, and Logo Carousel by cult-ui is the same pattern from a different registry. The masked edge matters more than the animation: without a fade at both ends, the logos appear to collide with the container and the row reads as broken rather than continuous.
One rule for this shape. It is decoration, so it must not be the only place a fact lives. If a logo is your proof, it belongs in the HTML as an image with alt text either way, not painted into a canvas that stops when the tab is backgrounded.




The stack
Cards in depth rather than in a row: one in front, the rest fanned behind it. It costs less width than a rail, which is why it survives on phones where a rail becomes a scroll.
CardStack by Ruixen UI is the full version, described by its author as a 3D card stack with fan-out animation, drag gestures and auto-advance. Card Fan Carousel by Aayush duhan is the arc-shaped take, with an elastic entrance and a hover spread, built on GSAP. 3D Carousel by cult-ui and Circular Gallery by Ravi Katiyar rotate the same idea into a ring.
These are the most fun and the most expensive. Every card is composited, usually with transforms and often with shadows, and on a mid-range Android a stack of ten with drag inertia is where the frame budget goes. Cap the rendered set and recycle rather than mounting everything.
The comparison slider
A different thing that shares the word. Image Comparison Slider by Le Thanh is the before-and-after handle: two images, one draggable divider. It has none of the carousel objections, because nothing is hidden and there is no timer, and it is the right control for exactly one job, which is showing a difference.




The accessibility part, which is where most of them fail
A carousel is one of the few patterns with a published, specific set of requirements, and the gap between the published version and the average implementation is wide. The failures are consistent.
Arrow buttons are not divs. They need to be real <button> elements with text, even if that text is visually hidden. "Next slide" and "Previous slide" read fine; a bare chevron reads as nothing.
Autoplay needs a pause, and it needs to stop by itself. Motion that starts automatically, lasts more than five seconds and runs beside other content is covered directly by WCAG 2.2.2, and the required answer is a mechanism to pause it. Practically: pause on hover, pause on focus anywhere inside the rail, and honour prefers-reduced-motion by not starting at all.
The offscreen slides are still in the DOM. If they are hidden with opacity or a transform, a screen reader still reads them and Tab still lands on their links. Use inert on inactive slides, or unmount them.
Native scroll beats a rebuilt one. overflow-x: auto with scroll-snap-type: x mandatory gives you keyboard scrolling, trackpad momentum, touch inertia and screen-reader support for free, all of which a transform-based track has to reimplement and usually does not. Reach for a library when you need loop, autoplay and virtualisation; do not reach for one to move a row sideways.
Every slide needs a stable focus order. If a card is a link, dragging it should not activate it. Distinguish drag from click by movement threshold, or the first swipe on a phone navigates away.
What to use for the mechanics
The visual layer is what the components above give you. The transport underneath is a smaller set of choices.
| Source | Best for | Trade-off |
|---|---|---|
| CSS scroll snap | Rails, galleries, anything without loop or autoplay | No infinite loop, no programmatic autoplay |
| Embla | The engine behind shadcn/ui's Carousel: loop, autoplay, drag, plugins | You are still writing the arrows, dots and slide markup |
| shadcn/ui Carousel | A wired Embla with keyboard and ARIA already handled | Plain by design; the visual patterns above sit on top of it |
| 21st | The finished shapes: stacks, fans, hover galleries, comparison sliders | Quality varies by author, so preview before you take it |
The split most teams land on: Embla or scroll snap for movement, a component from a catalogue for the look, and your own design system for the card inside.
Taking one
Every component page has a live preview and the code. Installing goes through the shadcn CLI against our registry:
That key comes from your 21st account, and installs require a membership. Set API_KEY_21ST once in your shell and the command works for anything in the catalogue. The 21st MCP covers the same ground without leaving the editor: ask Claude, Cursor or Codex for a carousel, get the previews inline, and let the agent write the file.
Frequently asked
- Are carousels bad for usability?
- Hero sliders are, and rails usually are not. The objection to an auto-advancing hero is that four of its five messages are invisible at any moment while the reader is trying to make one decision. A horizontal rail of peers, where the next card peeks past the edge and nothing is hidden that the reader needed, does not have that problem: moving is the point rather than a tax.
- How do you make a carousel accessible?
- Real button elements with text for the arrows, even if the text is visually hidden. A pause mechanism for anything that autoplays, which WCAG 2.2.2 requires for motion that starts on its own and runs beyond five seconds, plus pause on hover and focus and no autoplay at all under prefers-reduced-motion. Offscreen slides need inert or unmounting, otherwise a screen reader reads them and Tab lands inside them.
- Should I use a carousel library or CSS scroll snap?
- Scroll snap unless you need loop, autoplay or virtualisation. overflow-x: auto with scroll-snap-type gives you keyboard scrolling, trackpad momentum, touch inertia and screen reader support for free, all of which a transform-based track has to reimplement. Embla, which is what shadcn/ui's Carousel wraps, is the right answer once you genuinely need the transport features.
- Why does my carousel feel slow on mobile?
- Usually because every slide is mounted and composited at once. Depth effects multiply the cost: a fanned stack with shadows and drag inertia composites each card on every frame, which is where the budget goes on a mid-range Android. Cap the rendered set and recycle slides, drop shadows on touch, and distinguish drag from click by a movement threshold so the first swipe does not navigate away.