overflow, scroll-snap & keyboard access

Swipeable rows with scroll snap

Lesson 17 of 20 · 10 min · Module 5: Pages for every situation

Horizontal rows of cards are everywhere on phones. Scroll snap makes them land neatly on a card after each swipe, with pure CSS. The row must still work for keyboard users and must not make the whole page scroll sideways.

Start this lesson →

Free. No installation: you write and run the code in your browser, and it is checked automatically.

By the end, you’ll be able to…

  • Scroll a row inside its container
  • Snap scrolling to items with scroll-snap
  • Keep a scrolling region keyboard accessible

The idea

overflow-x: auto lets a row scroll inside itself, and scroll-snap-type: x mandatory makes it stop on snap points. Each slide sets scroll-snap-align: start. Slides with flex: 0 0 80% leave a peek of the next one, which tells people there is more. tabindex="0" and an aria-label let keyboard users focus the row and scroll it with the arrow keys.

.row {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}
.row > * { scroll-snap-align: start; }

01Scroll inside, not the page

overflow-x: auto contains the wide row, so only the row scrolls. Without it, the extra width pushes the whole page sideways on phones, which feels broken.

02Snap points

scroll-snap-type on the container turns snapping on; scroll-snap-align on each child says which edge snaps. mandatory always settles on a slide, while proximity only snaps when you stop close to one.

.carousel { scroll-snap-type: x mandatory; scroll-padding-inline: 16px; }
.slide { scroll-snap-align: start; }

03Keyboard and screen readers

A scrolling region with no focusable content cannot be reached with the keyboard. tabindex="0" makes it focusable, and aria-label gives it a name when focus arrives.

Your turn

1) Make .carousel scroll sideways with overflow-x: auto and snap with scroll-snap-type: x mandatory. 2) Give every .slide flex: 0 0 80% and scroll-snap-align: start. 3) Add tabindex="0" and aria-label="Featured courses" to the <ul class="carousel">. On a 390px screen the page itself must not scroll sideways.

What the checks look for

  • The row scrolls sideways
  • Scrolling snaps to the slides
  • Slides snap at their start
  • Each slide takes 80% of the row
  • Slides never shrink
  • Keyboard users can focus the named row
  • The page does not scroll sideways on a phone
Try it in the editor →

Take this with you

Scroll snap gives app-like swiping with plain CSS.

Go a little further

Add scroll-padding-inline: 16px to the row so snapped slides keep a little space from the edge.

Learn HTML & CSS Intermediate for free

20 short lessons with real code and instant checks.

See the whole course →