Carousel
الشريط الدوّارaria-roledescription="carousel"
also calledslider، image slider، slideshow، content rotator، hero slider، banner rotator، كاروسيل، سلايدر، شريط الشرائح، معرض منزلق، عارض دوّار، شرائح متحرّكة
A carousel shows a set of slides in one slot, one slide or a slide and a half at a time, and every slide has a position the user can reach with the arrows, with the dots, or by swiping. That position belongs to the user, and it gets announced and numbered: "3 of 6". A marquee is not this. It crawls without stopping, has no current slide, and offers no way back to what already passed, so it decorates rather than navigates. A plain horizontal scroller is not this either: it moves with a finger or a trackpad and nothing more, with no controls and no slide semantics in the accessibility tree, and for a row of products it is usually the better choice, because a clipped edge already tells people there is more. Tabs part company on one point, since a tab label describes the panel it opens while a dot describes nothing beyond its own position. One cost belongs in every review of this pattern: whatever sits after slide one is seen by a small fraction of visitors, so a price, a signup button, or an offer you need people to read does not go in there.
If you called it…
Live specimen
Interact with the demo. Every part is real and numbered.
Anatomy: every part, named
Hover a row to locate it in the demo above.
Build prompt
How it behaves right-to-left
This section is ours alone.
The inline axis reverses by itself
mirrorsSlide one starts at the right in Arabic and advancing moves leftward, which a scroll container, a flex track, and the dot row all do by themselves, because the inline axis follows direction. Do not flip it a second time: flex-direction: row-reverse under [dir="rtl"], or a reversed array in JavaScript, puts the visual order back the way English had it and leaves Tab order disagreeing with the eye. The exception is a track driven by transform: translateX(calc(-100% * var(--i))), since transforms know nothing about direction, so sign the offset with var(--dir) and set --dir: -1 inside [dir="rtl"].
The arrows: place, glyph, and job
mirrorsThe Previous button belongs at the logical start, which in Arabic is the right, so place the pair with inset-inline-start and inset-inline-end rather than left and right. The chevron drawing mirrors with them: put scaleX(-1) on a class you use for arrows alone, or swap the two icons. The job mirrors too, because Next now scrolls toward the left: write el.scrollBy({ left: step * dir }) with dir at -1 under RTL, and have the key handler read ArrowLeft as Next.
The sign of scrollLeft
mirrorsCurrent engines start at zero on the first slide and go negative as you advance, older WebKit started at the maximum positive value and counted down, and IE counted up from zero. Anything shaped like Math.round(scrollLeft / slideWidth) therefore returns a negative or wrong slide number in Arabic. Stay off the sign entirely: jump with slide.scrollIntoView({ inline: "start", block: "nearest" }), which is logical already, and derive the current slide by comparing each getBoundingClientRect against the logical edge of the viewport.
What CSS will not flip for you
mirrorsscroll-snap-align: start is flow relative, so it becomes the right edge in Arabic on its own, and scroll-snap-type: inline states the intent more precisely than x. scroll-padding-left, on the other hand, keeps the gutter on the left after the flip, so write scroll-padding-inline-start. The scrim over a hero image is worse, because neither gradients nor background-position accept flow-relative values at all: linear-gradient(to right, …) and background-position: left center both stay where they were, so they need an explicit override inside [dir="rtl"].
The artwork stays as drawn
never mirrorsThe photograph, a logo inside it, and the play and pause control of an autoplaying carousel keep their drawing in Arabic. The usual cause of a mirrored face or a backwards logo is a blanket rule like [dir="rtl"] svg, [dir="rtl"] img { transform: scaleX(-1) }, so reserve the flip for a class you put on the two arrows and nothing else. Playback controls point along the timeline rather than along the text, which is why the triangle faces the same way in both languages.
In code
Each row is one framework's word for the same thing. Take the row your project speaks.
See also
Updated · 2026-08-19