Introducing Native Carousel

July 29, 2021 5:54 am Published by Leave your thoughts

A carousel component which uses the native scroll snapping functionality with enhancements and customisation. It is lightweight and accessible, with vertical, auto height, tabs, lightbox, layout options, RTL support and no dependencies

Full site:

Why another carousel component

Native Carousel is as close as possible to the built-in browser capabilities (scrolling, real buttons etc) and while there are many similar tech demos around, this one is intended as complete product. The native web offers rich functionality and great UX with a little* coding and overcoming browser issues. Using Scroll Snapping lets the browser take care of swiping and scrolling and provides carousel interaction in the most natural way. It works without JavaScript, while there are a number of enhancements when the script is loaded.

How it works

The slides are grouped in a scrollable row and after snapping to a new position, the script updates the index. Buttons animate the scroll position.


  • Stable: Unbreakable structure with any length of content.
  • Accessibile: Arrow keys slide when the carousel is in focus. Keyboard-accessible buttons are used for controls. The “prefers reduced motion” setting is respected.
  • Performant: The native scroll is a fast way to move content around.
  • Featureful: Vertical option, visible neighbours, controls position options, auto height option, tabs option, auto slide option, detached controls option, Lightbox, inline Lightbox with modal, full screen option.
  • Compatible: Intended to work anywhere even without JS.
  • Natural: Swiping uses the native scrolling on trackpad and touch. No need to click, hold and swipe with the mouse, which makes elements inside the slides undraggable.
  • Lightweight: 7 KB total – 3.5 KB of CSS and optional 3.5 KB of JavaScript.
  • Embeddable: Carousel inside carousel works without limits.
  • Seamless integration in any page or context with BEM classes.
  • Modern: Scroll Snap, CSS Grid, Resize Observer etc.
  • Themeable with CSS variables
  • RTL support
  • No dependencies

How to use

Get the n-carousel NPM module and either add n-carousel.js and n-carousel.scss to your project or use n-carousel.min.js and n-carousel.min.css on your page.

The subpixel conundrum and other pitfalls

The initial concept is clear enough, but the state of all browsers made development harder than it should have been. Here are some of the issues encountered along the way:

  • Padding is not respected in a scrolling container,
  • Browsers eager to optimize and inconsistent in timing,
  • Browsers don’t keep scroll position on resize (fixed since),
  • Chrome freezes scroll snap when scrolling both directions during snapping,
  • Sub pixel dimensions unsupported in scroll position,
  • Scroll behavior “smooth” wasn’t used, because it’s unsupported by Safari and doesn’t allow custom duration,
  • el.animate() wasn’t used because it doesn’t support scroll,
  • Fun with mouse wheel, trackpad on Windows,
  • Wrapper bleeds subpixel content,
  • Safari resets scroll position after exit from full screen,
  • Safari floors this value: width: calc(100% – 0px) (fixed in v15),
  • Safari can’t animate scroll and height at once,
  • Safari can’t re-enable pointer events programmatically,
  • Safari resets scroll position when snapping is re-enabled (fixed in v15),
  • Safari not supporting snapping in RTL (fixed in v14).
  • And many more…

What’s next

  • Endless carousel
  • Cross fade/dissolve
  • Start from any slide, hash support
  • Multiple slides visible at once

Learn more at Thanks for supporting the open native web and happy scrolling!

Categorised in:

This post was written by rado

Leave a Reply

Your email address will not be published. Required fields are marked *