<scroll> creates a scrollable view component.

export default function App() {
  return <scroll style={{
    backgroundColor: 'white',
    padding: 20,
    width: 400,
    height: 120,
  }}>
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet molestiae officia sit numquam! Distinctio mollitia deserunt commodi iusto quam hic, in velit perspiciatis! Quaerat pariatur non, esse quam voluptatibus incidunt.
  </scroll>;
};

Scrolling

A wheel tick scrolls 100 points, which is near enough to what a browser does for one notch of the wheel. sensitivity is that distance, so sensitivity={50} halves it; a trackpad reports fractions of a tick and scales with it.

smoothness is how long the view takes to catch up with the wheel — 0.12 seconds by default, and 0 to follow it exactly. A wheel scroll has no destination, so it is a follow rather than a fixed animation: turning the wheel again moves the target and the motion carries on instead of restarting. A scroll that is given a destination — ScrollTo, ScrollTop, a snap — takes the time it was given instead. elasticity above 0 lets the content be pulled past its end and spring back, unless overscroll-behavior: none has taken that away. direction fixes which way the view scrolls, and alwaysShow keeps the named scrollbars from auto-hiding.

A view that has reached its end hands the rest of the scroll to the view above it; overscroll-behavior is how one keeps it. Scrolling to a position, animating that scroll and resting on the items inside are scroll-behavior and scroll-snap.

Scrollbars

The scrollbars are the ::scrollbar and ::scrollbar-thumb pseudo elements, and [horizontal] or [vertical] picks one of them. They can be styled like any element: width, height, background-color, border-radius, and left or top to move a bar to the opposite edge. The web’s ::-webkit-scrollbar, ::-webkit-scrollbar-track and ::-webkit-scrollbar-thumb name the same two elements, so a stylesheet written for a browser applies as it is.

The web properties are shortcuts for the common cases. scrollbar-color: <thumb> <track> colors both parts, and scrollbar-width: auto | thin | none | <length> sets the thickness (thin is 6px, none hides the bars). A ::scrollbar rule of your own still wins over them.

Scrollbars are drawn over the content, so nothing moves when one appears. scrollbar-gutter: stable reserves the bar’s thickness along its edge instead, for every direction the view can scroll in, so content is never covered; stable both-edges reserves the same amount on the opposite edge too, which keeps the content centered. The gutter follows scrollbar-width, so none reserves nothing.

scroll {
  scrollbar-color: #888 transparent;
  scrollbar-width: thin;
  scrollbar-gutter: stable;
}

scroll::scrollbar-thumb {
  border-radius: 3px;
}