Carousel

Carousels are for displaying a related set of content items in a row. Items can be paged using the next/previous buttons or by a swipe gesture.

  • Install
    npm install @pluralsight/ps-design-system-carousel
  • Import
    import Carousel from '@pluralsight/ps-design-system-carousel'

Examples

Size

The number and width of items in the Carousel are handled automatically. Item min and max width constraints will adjust based on the size prop passed the Carousel. Similarly, the number of items in the Carousel can be controlled by constraining the width of a container element around the Carousel.

The content that you pass as a child to Carousel.Item to be responsive. In the case of Card, a common item child, the width is 100%, infinitely flexible. If not sufficiently flexible, the carousel will not look great. If the child can't expand to fill the item, the gutters will be off. If the child can't shrink to fit the item, the paging will be off.

import Card from '@pluralsight/ps-design-system-card'
import Carousel from '@pluralsight/ps-design-system-carousel'
import React from 'react'
function Example() {
return (
Object.values(Carousel.sizes).map(size => (
<Carousel size={size}>
{MOCK_DATA.courses.map(course => (
<Carousel.Item key={course.id}>
<Card
image={
<Card.Image src="https://picsum.photos/seed/picsum/540/360" />
}
metadata1={[course.author, course.level]}
progress={randomInt()}
title={<Card.Title>{course.title}</Card.Title>}
/>
</Carousel.Item>
))}
</Carousel>
))
)
}
export default Example
const randomInt = (max = 100) => Math.floor(Math.random() * Math.floor(max))
const MOCK_DATA = {
courses: [
{
author: 'Jim Cooper',
id: '1',
level: 'Intermediate',
title: 'Vue.js Fundamentals'
},
{
author: 'Mark Heath',
id: '2',
level: 'Intermediate',
title: 'Azure Functions Fundamentals'
},
{
author: 'Kyle Simpson',
id: '3',
level: 'Advanced',
title: 'Advanced JavaScript'
},
{
author: 'Mark Zamoyta',
id: '4',
level: 'Advanced',
title: 'Rapid JavaScript Training'
},
{
author: 'Dan Wahlin',
id: '5',
level: 'Advanced',
title: 'Structuring JavaScript Code'
},
{
author: 'Jim Cooper',
id: '6',
level: 'Advanced',
title: 'JavaScript Objects and PropTypes'
},
{
author: 'Jim Cooper',
id: '11',
level: 'Intermediate',
title: 'Vue.js Fundamentals'
},
{
author: 'Mark Heath',
id: '12',
level: 'Intermediate',
title: 'Azure Functions Fundamentals'
},
{
author: 'Kyle Simpson',
id: '13',
level: 'Advanced',
title: 'Advanced JavaScript'
},
{
author: 'Mark Zamoyta',
id: '14',
level: 'Advanced',
title: 'Rapid JavaScript Training'
},
{
author: 'Dan Wahlin',
id: '15',
level: 'Advanced',
title: 'Structuring JavaScript Code'
},
{
author: 'Jim Cooper',
id: '16',
level: 'Advanced',
title: 'JavaScript Objects and PropTypes'
},
{
author: 'Jim Cooper',
id: '21',
level: 'Intermediate',
title: 'Vue.js Fundamentals'
},
{
author: 'Mark Heath',
id: '22',
level: 'Intermediate',
title: 'Azure Functions Fundamentals'
},
{
author: 'Kyle Simpson',
id: '23',
level: 'Advanced',
title: 'Advanced JavaScript'
},
{
author: 'Mark Zamoyta',
id: '24',
level: 'Advanced',
title: 'Rapid JavaScript Training'
},
{
author: 'Dan Wahlin',
id: '25',
level: 'Advanced',
title: 'Structuring JavaScript Code'
},
{
author: 'Jim Cooper',
id: '26',
level: 'Advanced',
title: 'JavaScript Objects and PropTypes'
}
]
}

Use portals for overflow

If there are any UI elements that need to appear in the same visual space as the carousel container, they will need to be rendered outside the Carousel DOM. This is because the Carousel container solution requires being styled overflow: hidden. A React Portal is a great solution. A common example could be an ActionMenu rendered from a Card. Here is some example code:

import ActionMenu from '@pluralsight/ps-design-system-actionmenu'
import { BelowRight } from '@pluralsight/ps-design-system-position'
import Card from '@pluralsight/ps-design-system-card'
import Carousel from '@pluralsight/ps-design-system-carousel'
import { MoreIcon } from '@pluralsight/ps-design-system-icon'
import React from 'react'
function Example() {
return (
<Carousel size={Carousel.sizes.wide}>
{MOCK_DATA.courses.map(course => (
<Carousel.Item key={course.id}>
<Toggle>
{({ active, toggle }) => (
<Card
image={<Card.Image src={course.image} />}
metadata1={[course.author, course.level]}
title={<Card.Title>{course.title}</Card.Title>}
actionBarVisible
actionBar={[
<BelowRight
inNode={typeof document !== 'undefined' && document.body}
when={active}
show={
<ActionMenu onClick={toggle}>
<ActionMenu.Item>Useless item</ActionMenu.Item>
<ActionMenu.Item>Useless item</ActionMenu.Item>
<ActionMenu.Item>Useless item</ActionMenu.Item>
<ActionMenu.Item>Useless item</ActionMenu.Item>
<ActionMenu.Item>Useless item</ActionMenu.Item>
<ActionMenu.Item>Useless item</ActionMenu.Item>
<ActionMenu.Item>Useless item</ActionMenu.Item>
<ActionMenu.Item>Useless item</ActionMenu.Item>
</ActionMenu>
}
key="a"
>
<Card.Action
title="See more"
icon={<MoreIcon />}
onClick={toggle}
/>
</BelowRight>
]}
/>
)}
</Toggle>
</Carousel.Item>
))}
</Carousel>
)
}
export default Example
function Toggle(props) {
const [active, setActive] = React.useState(
typeof props.active === 'undefined' ? !!props.startActive : !!props.active
)
function toggle() {
setActive(!active)
}
return props.children({ active, toggle })
}
const MOCK_DATA = {
courses: [
{
author: 'Jim Cooper',
id: '1',
level: 'Intermediate',
title: 'Vue.js Fundamentals'
},
{
author: 'Mark Heath',
id: '2',
level: 'Intermediate',
title: 'Azure Functions Fundamentals'
},
{
author: 'Kyle Simpson',
id: '3',
level: 'Advanced',
title: 'Advanced JavaScript'
},
{
author: 'Mark Zamoyta',
id: '4',
level: 'Advanced',
title: 'Rapid JavaScript Training'
},
{
author: 'Dan Wahlin',
id: '5',
level: 'Advanced',
title: 'Structuring JavaScript Code'
},
{
author: 'Jim Cooper',
id: '6',
level: 'Advanced',
title: 'JavaScript Objects and PropTypes'
},
{
author: 'Jim Cooper',
id: '11',
level: 'Intermediate',
title: 'Vue.js Fundamentals'
},
{
author: 'Mark Heath',
id: '12',
level: 'Intermediate',
title: 'Azure Functions Fundamentals'
},
{
author: 'Kyle Simpson',
id: '13',
level: 'Advanced',
title: 'Advanced JavaScript'
},
{
author: 'Mark Zamoyta',
id: '14',
level: 'Advanced',
title: 'Rapid JavaScript Training'
},
{
author: 'Dan Wahlin',
id: '15',
level: 'Advanced',
title: 'Structuring JavaScript Code'
},
{
author: 'Jim Cooper',
id: '16',
level: 'Advanced',
title: 'JavaScript Objects and PropTypes'
},
{
author: 'Jim Cooper',
id: '21',
level: 'Intermediate',
title: 'Vue.js Fundamentals'
},
{
author: 'Mark Heath',
id: '22',
level: 'Intermediate',
title: 'Azure Functions Fundamentals'
},
{
author: 'Kyle Simpson',
id: '23',
level: 'Advanced',
title: 'Advanced JavaScript'
},
{
author: 'Mark Zamoyta',
id: '24',
level: 'Advanced',
title: 'Rapid JavaScript Training'
},
{
author: 'Dan Wahlin',
id: '25',
level: 'Advanced',
title: 'Structuring JavaScript Code'
},
{
author: 'Jim Cooper',
id: '26',
level: 'Advanced',
title: 'JavaScript Objects and PropTypes'
}
]
}

Guidelines

The height of the carousel adapts to the height of the content it contains, but the width of its children will be equalized, so make sure to use related content for children that are intended to be used at the same height and width.

Do
Don't

Accessibility

WCAG 2.1 AA Compliance

100% axe-core tests
Manual audit

WAI-ARIA Patterns: Carousel

Props

Name
Type
Description
Default
children
Required
Carousel.Itemitems to place in carousel
size
small | medium | large
size of carousel itemsmedium

Carousel.Controls

Name
Type
Description
Default
children
Required
React.ReactNodecontrols to advance carousel frames

Carousel.Control

Name
Type
Description
Default
direction
Required
prev | next
(from Carousel.Control.directions)

Carousel.Item

Name
Type
Description
Default
children
Required
React.ReactNode | () => React.ReactNoderender prop used to access item and page metadata