Scroll

Modern CSS can handle smooth scrolling, hidden scrollbars, and snapping carousels natively — no scroll library required. Scroll utilities expose that native behavior as simple, composable classes.

Scroll Behavior

.scroll-smooth { scroll-behavior: smooth; }
.scroll-auto { scroll-behavior: auto; }

scroll-behavior controls what happens when the scroll position changes programmatically — clicking an in-page anchor link (<a href="#section">), or calling element.scrollIntoView() in JavaScript. .scroll-smooth animates that jump instead of snapping instantly to position. It has no effect on the user's own manual scrolling (mouse wheel, trackpad, touch) — that always stays instant and under the user's control.

<html class="scroll-smooth">
  <!-- in-page anchor links now animate to their target -->
</html>

Since .scroll-smooth doesn't itself respect prefers-reduced-motion, projects that need to honor that setting strictly should pair it with a reduced-motion override in their own CSS.

Hiding the Scrollbar

.no-scrollbar {
  -ms-overflow-style: none; /* IE and Edge */
  scrollbar-width: none; /* Firefox */
}

.no-scrollbar::-webkit-scrollbar {
  display: none; /* Chrome, Safari and Opera */
}

Three separate rules are needed because no single CSS property hides scrollbars across every engine: -ms-overflow-style for legacy IE/Edge, scrollbar-width for Firefox, and the ::-webkit-scrollbar pseudo-element for Chromium and Safari.

.no-scrollbar only hides the visual track — the element remains fully scrollable by touch, wheel, and keyboard. Because that also removes the usual visual cue that content overflows, pair it with another affordance (a fade-out gradient at the edge, visible pagination dots) so users can still tell there's more to scroll.

Scroll Snap

Scroll snap is split into two independent pieces: snap type, set on the scrolling container, and snap align, set on each child. This mirrors the native CSS Scroll Snap spec, and keeps the two decisions — "does this container snap, and how strictly" vs. "where does each item align" — fully decoupled.

Container: Snap Type

.snap-none { scroll-snap-type: none; }
.snap-x { scroll-snap-type: x var(--scroll-snap-strictness, mandatory); }
.snap-y { scroll-snap-type: y var(--scroll-snap-strictness, mandatory); }
.snap-both { scroll-snap-type: both var(--scroll-snap-strictness, mandatory); }
.snap-mandatory { --scroll-snap-strictness: mandatory; }
.snap-proximity { --scroll-snap-strictness: proximity; }

.snap-x, .snap-y, and .snap-both set the snapping axis, reading their strictness from the --scroll-snap-strictness custom property — which defaults to mandatory if nothing else sets it. .snap-mandatory and .snap-proximity don't touch scroll-snap-type directly; they only set that custom property, which the axis class then consumes. That split means axis and strictness can be combined in any order in your class list:

CombinationBehavior
snap-x snap-mandatoryAlways snaps to a point after scrolling on the x-axis
snap-x snap-proximitySnaps only if the scroll happens to end near a point — feels looser
snap-x (alone)Defaults to mandatory strictness

Children: Snap Align

.snap-start { scroll-snap-align: start; }
.snap-center { scroll-snap-align: center; }
.snap-end { scroll-snap-align: end; }
.snap-align-none { scroll-snap-align: none; }

These go on the items inside the snapping container, and determine which edge of each item aligns to the container's snap point.

Building a Snap Carousel

Putting scroll behavior, hidden scrollbars, and snap together produces a fully native carousel — no JS, no dependency:

<div class="flex snap-x snap-mandatory scroll-smooth no-scrollbar overflow-x-auto">
  <div class="snap-center shrink-0 w-80">Slide 1</div>
  <div class="snap-center shrink-0 w-80">Slide 2</div>
  <div class="snap-center shrink-0 w-80">Slide 3</div>
</div>

overflow-x-auto makes the row scrollable, snap-x snap-mandatory locks it to always land on a slide, snap-center on each child aligns it to the middle of the viewport, scroll-smooth animates any programmatic jumps (like "next" arrow buttons), and no-scrollbar keeps the track visually clean.

FrontAlign