Replies: 52 comments
-
Carousel ResearchReal world examplesGoogle cast
Netflix
Squarespace
Usain Bolt
Mercedes Benz
Toyota
Lib examplesBootstraphttps://react-bootstrap.github.io/components/carousel/
React carouselhttps://brainhubeu.github.io/react-carousel/
Slickhttps://kenwheeler.github.io/slick/
Flickityhttps://flickity.metafizzy.co/
React Responsive Carouselhttps://react-responsive-carousel.js.org/
Comprehensive featuresLooking at the above, the spectrum of available features appears to be the following. I've made these checkboxes so we can agree which we would like to support.
Please feel free to and add anything not covered here to the list! Once agreed on these, I'll propose an API 👍 Questions
|
Beta Was this translation helpful? Give feedback.
-
Great start. Can't believe there's not a My biggest concern with drag-to-slide is how it works when composed with other draggable/slideable components composed within the carousel. Are nested carousels supported in any case? What about |
Beta Was this translation helpful? Give feedback.
-
In the Usain Bolt example, I imagine these slide previews might overflow at certain widths, and they too would become independently draggable. A carousel inside a carousel. 🙃 |
Beta Was this translation helpful? Give feedback.
-
Probably worth adding https://flickity.metafizzy.co/ to the list as well. That's arguably one of the best out there I think. |
Beta Was this translation helpful? Give feedback.
-
Your wish is my command 😛
Yeah I was also wondering what sort of media we think should be allowed in these. Are we happy to say they are an open box or would we expose something like |
Beta Was this translation helpful? Give feedback.
-
My thought is that it probably has to be a bit of an open box, but it's potentially problematic even with non-interactive content in ways I haven't considered fully. I'd probably want to still be able to select text with a mouse, for example. I wonder if it would be worth trying to detect the intent of a particular action -- is the user clicking or touching to pressing something, or are they intending to drag? I'd be interested to see how/if React Aria handles this when |
Beta Was this translation helpful? Give feedback.
-
Some notes after chatting through the discovery with @jjenzz. The feature list posted above looks solid. Two things that require further thinking:
Some notes to clarify particular features: Prev/Next Buttons
Thumbails Decouple events from scrolling It works well for image gallery carousels, the kind you see when you click an image in an image grid on Twitter or FB. But there are many cases where you want the touch/swipe/trackpad interactions to function as a normal scroll area, with only the next/prev and indicator buttons sliding a whole pane. Some research is required here to figure out exactly how best to manage this. Option to disable swiping on pointer devices Indicators
isScrolling state Autoplay
Cursor key navigation Many carousels have focusable content in each slide. For example, focusable cards on Deliveroo, focusable cards on Netflix, tabs in a carousel on Youtube etc. So we need to ensure that, for example, cursor key navigation still works on tabs, even though each tab would be inside an element like Nested carousels
|
Beta Was this translation helpful? Give feedback.
-
I really really like where this is going!
There is something interesting related to this in Flickity which I haven't seen many libs support and we haven't mentioned here: variable width cells (ie. images of differents widths/ratios for example). This is kinda important I would say, and does change the way things will have to be calculated probably (especially around swiping, etc).
I am a little confused by this section, would you mind posting image examples of each things you have in mind for these here? |
Beta Was this translation helpful? Give feedback.
-
I didn't think of this, so we should probably look into it a little. I see some carousel libs support it, but off the top of my head, I can't think of any valid use cases or any existing examples in the wild. It seems like it would always be a bad design.
On Netflix in the screenshot posted above, the indicators reflect the number of panes/pages available, not the number of total slides. In other carousels, like social media stories (Fleets, IG Stories, FB Stories etc.), the indicators reflect the total number of slides/items. In both of the cases I've just mentioned, the indicators are not interactive. But often, you would want interactive indicators like the little button dots you mentioned. |
Beta Was this translation helpful? Give feedback.
-
Here's one of the flickity examples: https://codepen.io/desandro/pen/GgQREP
Ah ok I see, I wasn't clear on whether you meant the numbers should actually appear on the page (like 3/5). I see what you're saying now, meaning how many indicators based on if they're indicating slides or panes, gotcha. |
Beta Was this translation helpful? Give feedback.
-
I would file this under "bad design". It's passable in this exact case (the full-width carousel), but still bad. The image should be centered horizontally and vertically inside a fixed-width container. In a typical image gallery, where you're viewing a single image at a time (the kind on Twitter/IG/FB etc.), this would be very bad. You never want the UI (next/prev buttons etc.) around the image to shift. So the container should always be the same size, and the image is centered inside it. So at this point, I'd still file this under "not important at all", and potentially even "we should actively discourage this". |
Beta Was this translation helpful? Give feedback.
-
🤔 I don't see anything shifting on this example. But anyway, just making sure we capture all the things out there. |
Beta Was this translation helpful? Give feedback.
-
This is still very much in DRAFT, but wanted to jot down progress so far in case there are any opinions on this direction so far: AnatomySee bullets below for detailed explanation of various bits. <Carousel
as="div" // default `div`
slidesPerPage={2} // default `auto`
loop={false} // default `true`?
page={1} // default `undefined`
defaultPage={1} // default `undefined`
onPageChange={page => {}} // default `undefined`
onScroll={event => {}} // default `undefined`
onDragScroll={event => {}} // default `undefined`
>
<CarouselSlide as="div" />
<CarouselSlide as="div" />
<CarouselSlide as="div" />
<CarouselSlide as="div" />
<CarouselSlide as="div" />
<CarouselSlide as="div" />
<CarouselSlide
as="div"
autoFocus // Scrolls into view
/>
{/* non-interactive indicator */}
<CarouselIndicator as="ol">
<CarouselIndicatorItem as="li" />
</CarouselIndicator>
{/* interactive indicator */}
<CarouselIndicator as="ol">
<CarouselIndicatorItem as="li">
<CarouselIndicatorButton as="a" />
</CarouselIndicatorItem>
</CarouselIndicator>
<CarouselButtonPrevious as="button" />
<CarouselButtonNext as="button" />
</Carousel>
|
Beta Was this translation helpful? Give feedback.
-
A couple of initial thoughts, but otherwise I love the proposed API!
Didn't see this as an option in your post, but what about: <CarouselIndicator as="ol">
{({ pages }) => pages.map((page) => (
<CarouselIndicatorItem as="li" key={page.id}>
<CarouselIndicatorButton as="button" aria-label={page.title}>
<img alt="" />
</CarouselIndicatorButton>
</CarouselIndicatorItem>
))}
</CarouselIndicator> |
Beta Was this translation helpful? Give feedback.
-
Yep, I think we're all agreed we need this but as Colm touched on above, we're thinking that could be the second release of this (which we could work on right away if we wanted to). There are features like When we come to do that work, perhaps we will realise it should just be part of
Nope. I'm imagining it much like
So, if they have
That is the same as my proposal I believe except I meant we would do the map under the hood for them. I think I confused the situation by rendering <CarouselIndicator>
{({ page }: { page: number }) => (
<CarouselIndicatorItem>
<CarouselIndicatorButton>
Page {page}
</CarouselIndicatorButton>
</CarouselIndicatorItem>
)}
</CarouselIndicator> There is no I'm just not sure if this pattern is worth it for our first release. This is the sort of thing I'd prefer to pass on personally until we understand how people are using it and it is specifically requested for something that cannot be achieved without it. I'm struggling to think of genuine use-cases that |
Beta Was this translation helpful? Give feedback.
-
Looking forward to this. Any updates, please? |
Beta Was this translation helpful? Give feedback.
-
I don't understand why this carousel component was not integrated into the radix-ui primitive, as it is already used on the radix-ui.com website 🤔 There is already an existing component: https://github.com/radix-ui/website/blob/main/components/marketing/Carousel.tsx |
Beta Was this translation helpful? Give feedback.
-
@Vintotan That's weird |
Beta Was this translation helpful? Give feedback.
-
@Vintotan tmk, the version on the website is an incomplete version of the accessible carousel we were building that supports the website's specific use-case. carousels come with some complex a11y requirements that we never got around to finishing (especially if it is to be customisable) hence why it was not added to radix yet. |
Beta Was this translation helpful? Give feedback.
-
Can we have a simple version that not so customizable first, then optimize later? Is that anything we can help? |
Beta Was this translation helpful? Give feedback.
-
@jjenzz Do you have any update for this? We would really love to see it implemented! |
Beta Was this translation helpful? Give feedback.
-
Any update on this issue :) |
Beta Was this translation helpful? Give feedback.
-
Also interested in this being added to Radix! |
Beta Was this translation helpful? Give feedback.
-
Pretty please, give us a carousel primitive 🥺🙏🏼 |
Beta Was this translation helpful? Give feedback.
-
@jjenzz Is this something that will be developed, or should we assume any progress has been paused for the rest of the year? Our team needs to know if we need to begin searching outside of the Radix UI primitives for this, or if we can hold off until this is out. We'd love to hear an update form your end 🙏 |
Beta Was this translation helpful? Give feedback.
-
I don't think carousels are needed in Radix. Carousels are not a primitive. So I can understand why they don't want to do it. (Also, Radix has no responsibility to your team needing to know anything). Carousels should be used with care, designers always seem to do the old "can we just…" dance with them, and they get complex quickly. KISS approach with a working 1st version is best. Instead, use this simple typescript hook with CSS scroll-snap and get it to done. |
Beta Was this translation helpful? Give feedback.
-
And in the new Radix UI components that are prestyled? |
Beta Was this translation helpful? Give feedback.
-
What is and is not a primitive is subjective. Plenty of the "primitives" in Radix are not direct HTML element wrappers like . Most UI libraries offer a Carousel because of how frequently that are needed.
If they have no plans on implementing this, then they should state so and close this issue. Otherwise, teams are being delayed. |
Beta Was this translation helpful? Give feedback.
-
Bumping this up—I'd way rather use a Radix native carousel than grab from react-responsive-carousel! Another point in favor (although obviously — maintainers may have a reason, etc) is that shadcn (essentially Radix + Tailwind) has its own Carousel component! https://ui.shadcn.com/docs/components/carousel Will probably use theirs, but makes it messy because I am anti-tailwind / prefer vanilla Radix. What do maintainers think about this? Busy for a bit / wouldn't be for the next few weeks, but if maintainers are open to this I'd be happy to take a crack at adapting Shadcn's carousel back to radix standards and getting a PR up |
Beta Was this translation helpful? Give feedback.
-
@lucasgelfond bear in mind that shadcn's solution is just Embla. I just ended up using Embla, skipping shadcn, when I faced the same problem, and works well. |
Beta Was this translation helpful? Give feedback.
-
See #375
Beta Was this translation helpful? Give feedback.
All reactions