Skip to main content
Carousel
@coinbase/cds-web@8.47.1
A flexible carousel component for displaying sequences of content with navigation and pagination options.
import { Carousel } from '@coinbase/cds-web/carousel/Carousel'

Basics

Carousels are a great way to showcase a list of items in a compact and engaging way. By default, Carousels have navigation and pagination enabled. You can also add a title to the Carousel by setting title prop.

You simply wrap each child in a CarouselItem component, and can optionally set the width prop to control the width of the item.

You can also set the styles prop to control the styles of the carousel, such as the gap between items.

Images

Images inside of the carousel have pointer-events disabled by default.

Loading...

Item Sizing

Items by default take their natural width while in the carousel, such as from our example above. However, you can set the width prop of CarouselItem to control the width of the item.

Dynamic Sizing

Items can be given a width proportional to the carousel width.

Tip

If you have a gap between items, you should account for that in the width. For example, if you have a gap of 16px, and you want to show 2 items per page, you should give each item a width of calc(50% - 8px).

Loading...

Responsive Sizing

You can also use responsive props to change the number of items visible based on the carousel width. The carousel below will show per page 1 item on mobile, 2 items on tablet, and 3 items on desktop.

Loading...

Varied Sizing

Not all carousel items need to be the same size. You can provide CarouselItems of varying widths as well.

Loading...

Drag

You can set the drag prop to snap (default), free, or none. When set to snap, upon release the carousel will snap to either the nearest item or page (depending on snapMode).

Loading...

Snap Mode

You can set the snapMode to page (default) or item. When set to page, the carousel will automatically group items into pages. When set to item, the carousel will snap to the nearest item.

Loading...

Overflow

By default, the carousel's inner overflow is visible. This means that you can apply padding to the inner carousel element (such as styles={{ carousel: { paddingInline: 'var(--space-3)' } }}) and it will not be clipped. You can pair this with modifying the spacing of the inner carousel to match the padding of your page (along with a wrapping div to negate any default spacing). This creates a seamless experience.

Tip

If you want to have the next item be shown at the edge of the screen, make sure your carousel padding is larger than your gap.

Loading...

Autoplay

Use autoplay to allow for automatic page advancement. The default interval is 3 seconds but can be changed with autoplayInterval.

It is recommended to use pagination with autoplay so users know how many pages there are, and you should also set paginationVariant="dot" to best indicate the active page and progress.

Loading...

Looping

Use loop to allow for infinite scrolling.

Loading...

Accessibility

The carousel is accessible by default, and works best with interactive elements that can be focused. Users can navigate via keyboard or voiceover and will switch pages as they navigate through the carousel.

Each carousel item should have proper text within the focusable element or you use accessibilityLabel or accessibilityLabelledBy props to provide a label.

While not recommended, if your carousel has disabled drag, you can use isVisible render prop to prevent users from focusing on carousel items that are not visible.

<Carousel paginationVariant="dot" drag="none">
<CarouselItem id="btc" accessibilityLabel="Bitcoin">
<SquareAssetCard imageUrl={assets.btc.imageUrl} name={assets.btc.symbol} />
</CarouselItem>
<CarouselItem id="recurring-buy" width="100%" accessibilityLabelledBy="recurring-buy-label">
{({ isVisible }) => (
<UpsellCard
action={
<Button
compact
flush="start"
numberOfLines={1}
onClick={NoopFn}
tabIndex={isVisible ? undefined : -1}
variant="secondary"
>
Get started
</Button>
}
description="Want to add funds to your card every week or month?"
media={
<Box bottom={6} position="relative" right={24}>
<Pictogram dimension="64x64" name="recurringPurchases" />
</Box>
}
minWidth="0"
title={
<Text as="h3" font="headline" id="recurring-buy-label">
Recurring Buy
</Text>
}
width="100%"
/>
)}
</CarouselItem>
</Carousel>

Autoplay

You should note use hideNavigation and autoplay together, unless you provide an alternative pause mechanism. See this example with custom autoplay controls as an example.

Accessibility Labels

The Carousel provides several props to customize accessibility labels for screen reader users

<Carousel
nextPageAccessibilityLabel="Go to next slide"
previousPageAccessibilityLabel="Go to previous slide"
paginationAccessibilityLabel={(pageIndex) => `Go to page ${pageIndex + 1}`}
autoplayAccessibilityLabel="Play/pause carousel"
pageChangeAccessibilityLabel={(activePageIndex, totalPages) =>
`Showing page ${activePageIndex + 1} of ${totalPages}`
}
>
...
</Carousel>

Customization

Custom Components

You can customize the navigation and pagination components of the carousel using the NavigationComponent and PaginationComponent props. You can also modify the title by providing a ReactNode for the title prop.

Loading...

Custom Styles

You can use the classNames and styles props to customize different parts of the carousel.

Loading...

Custom Autoplay Controls

You can use useCarouselAutoplayContext inside a custom PaginationComponent to build your own controls. This example shows a composed layout with pagination and play/pause on the left, and navigation arrows on the right.

Loading...

Dynamic Content

You can dynamically add and remove items from the carousel.

Loading...

You can also animate items as they enter or leave the viewport.

Loading...

You can even change the size or content of items. In the example below, click an asset to highlight it.

Loading...

Hide Navigation and Pagination

You can hide the navigation and pagination components of the carousel if desired (using hideNavigation and hidePagination props).

Note that this can prevent proper accessibility for the carousel, if carousel items are not focusable. If hiding pagination, it's recommended instead to pass in DefaultCarouselNavigation with hideUnlessFocused prop. Alternatively, you can ensure that the carousel is navigable by keyboard through other means.

Loading...

Animated Pagination

You can create smooth pagination animations by customizing the pagination dots. This example shows how to create expanding dots that smoothly transition between active and inactive states.

Loading...

Imperative API

You can control the carousel programmatically using a ref. The carousel exposes methods to navigate to specific pages and access the current page index.

Loading...

Callbacks

You can use the onChangePage, onDragStart, and onDragEnd callbacks to listen for user interaction in the carousel.

<Carousel
paginationVariant="dot"
onChangePage={(pageIndex: number) => console.log('Page changed', activePageIndex)}
onDragStart={() => console.log('Drag started')}
onDragEnd={() => console.log('Drag ended')}
>
...
</Carousel>

Is this page useful?

Coinbase Design is an open-source, adaptable system of guidelines, components, and tools that aid the best practices of user interface design for crypto products.