Card

A card is a summary representation of a piece of content and typically is used in a horizontal row or grid of related content.

  • Install
    npm install @pluralsight/ps-design-system-card
  • Import
    import Avatar from '@pluralsight/ps-design-system-card'

Examples

In-app example

The card is a flexible component that will fit the container it's given. A gallery is a common container layout that one might encounter in the product. This is an example implementation of how the Card might look in a gallery in your app, using the Layout.EqualColumnLayout component.

  • Path
    Advanced TypeScript
  • J
    Getting Started with Reactive Programming Using RxJS
  • Building a JavaScript Development Environment"
  • Webpack Fundamentals"
import Avatar from '@pluralsight/ps-design-system-avatar'
import Card from '@pluralsight/ps-design-system-card'
import { BookmarkIcon, MoreIcon, PathIcon, PlayCircleIcon } from '@pluralsight/ps-design-system-icon'
import { EqualColumnLayout } from '@pluralsight/ps-design-system-layout'
function Example() {
return (
<EqualColumnLayout>
<ul>
<li>
<Card
tag={<Card.Tag icon={<PathIcon />}>Path</Card.Tag>}
title={<Card.Title>Advanced TypeScript</Card.Title>}
progress={0}
image={
<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />
}
metadata1={['Brice Wilson', 'Advanced']}
metadata2={['0m watched']}
size={Card.sizes.small}
/>
</li>
<li>
<Card
bonusBar={<Avatar size={Avatar.sizes.xSmall} name="Jake Trent" />}
title={
<Card.Title>
Getting Started with Reactive Programming Using RxJS
</Card.Title>
}
progress={20}
image={
<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />
}
metadata1={['Scott Allen', 'Intermediate']}
metadata2={['23m watched']}
size={Card.sizes.small}
/>
</li>
<li>
<Card
actionBar={[
<Card.Action
key="1"
title="Book action"
icon={<BookmarkIcon />}
/>,
<Card.Action key="2" title="More action" icon={<MoreIcon />} />
]}
title={
<Card.Title>
Building a JavaScript Development Environment"
</Card.Title>
}
fullOverlay={
<Card.FullOverlayLink>
<a>
<PlayCircleIcon size={PlayCircleIcon.sizes.large} />
</a>
</Card.FullOverlayLink>
}
progress={67}
image={
<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />
}
metadata1={['Cory House', 'Intermediate']}
metadata2={['3h 23m watched']}
size={Card.sizes.small}
/>
</li>
<li>
<Card
actionBar={[
<Card.Action
key="1"
title="Bookmark action"
icon={<BookmarkIcon />}
/>,
<Card.Action key="2" title="More action" icon={<MoreIcon />} />
]}
actionBarVisible
title={<Card.Title>Webpack Fundamentals"</Card.Title>}
progress={100}
metadata1={['Joe Eames', 'Intermediate']}
metadata2={['90m watched']}
image={
<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />
}
size={Card.sizes.small}
/>
</li>
</ul>
</EqualColumnLayout>
)
}
export default Example

Size

While the component is flexible, the size will determine certain base proportions and flexibility min and max bounds.

Large card
Medium card
Small card
import Card from '@pluralsight/ps-design-system-card'
import React from 'react'
function Example() {
return (
<div className="example-grid--spaced">
<div style={{ maxWidth: '540px' }}>
<Card
size={Card.sizes.large}
title={<Card.Title>Large card</Card.Title>}
metadata1={['Jim Cooper']}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
<div style={{ maxWidth: '320px' }}>
<Card
size={Card.sizes.medium}
title={<Card.Title>Medium card</Card.Title>}
metadata1={['Jim Cooper']}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
<div style={{ maxWidth: '140px' }}>
<Card
size={Card.sizes.small}
title={<Card.Title>Small card</Card.Title>}
metadata1={['Jim Cooper']}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
</div>
)
}
export default Example

Image

The image will cover the space given. This space is variable width but set height according to the size property.

To ensure screen-readable text, always pass aria-label for the image description.

Linked image with other overlays
import Button from '@pluralsight/ps-design-system-button'
import Card from '@pluralsight/ps-design-system-card'
import { BookmarkIcon } from '@pluralsight/ps-design-system-icon'
import React from 'react'
function Example() {
return (
<div style={{ maxWidth: '320px' }}>
<Card
image={
<Card.ImageLink>
<a href="https://google.com" target="_blank">
<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />
</a>
</Card.ImageLink>
}
title={<Card.Title>Linked image with other overlays</Card.Title>}
actionBar={[
<Card.Action
key="1"
title="Bookmark action"
icon={<BookmarkIcon />}
/>
]}
fullOverlay={
<Card.FullOverlayLink>
<a href="https://google.com?q=full%20overlay" target="_blank">
Full Overlay
</a>
</Card.FullOverlayLink>
}
/>
</div>
)
}
export default Example

Progress

Progress, if given, should be a number between 0 and 100 that describes the completion level of the content represented on the card.

The Card Title
The Card Title
import Card from '@pluralsight/ps-design-system-card'
import React from 'react'
function Example() {
return (
<div className="example-grid--col-2">
<div style={{ width: '320px' }}>
<Card
progress={25}
title={<Card.Title>The Card Title</Card.Title>}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
<div style={{ width: '320px' }}>
<Card
progress={100}
title={<Card.Title>The Card Title</Card.Title>}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
</div>
)
}
export default Example

Title

The title can be a string or a some other element, such as a link, that contains a string

Strings are line-clamped to 2 lines max, then the text will overflow with an ellipsis appended.

Super Long Title of the Technology of the Century as Brought to You By Tech Groupsoft in the Stunning Desert of British Lithuania
import Card from '@pluralsight/ps-design-system-card'
import React from 'react'
function Example() {
return (
<div className="example-grid--col-2">
<div style={{ width: '320px' }}>
<Card
title={
<Card.Title>
Super Long Title of the Technology of the Century as Brought to
You By Tech Groupsoft in the Stunning Desert of British Lithuania
</Card.Title>
}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
<div style={{ width: '320px' }}>
<Card
title={
<Card.TextLink>
<a>
<Card.Title>
Link with Super Long Title of the Technology of the Century as
Brought to You By Tech Groupsoft in the Stunning Desert of
British Lithuania
</Card.Title>
</a>
</Card.TextLink>
}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
</div>
)
}
export default Example

Metadata

Metadata is free-form strings or displayable elements like links. Each bit of metadata is separated by an interpunct.

Metadata is constrained to a single line, overflowing with an ellipsis indicated. The first datum is given display space precedence.

Card with Two Lines of Meta
Super-long Metadata
import Card from '@pluralsight/ps-design-system-card'
import React from 'react'
function Example() {
return (
<div className="example-grid--col-2">
<div style={{ width: '320px' }}>
<Card
metadata1={['Simon Allardice']}
metadata2={['Intermediate', '2h 20m', 'July 24, 1847']}
title={<Card.Title>Card with Two Lines of Meta</Card.Title>}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
<div style={{ width: '320px' }}>
<Card
metadata1={[
<Card.TextLink>
<a href="https://google.com?query=simon%20allardice">
The Honorable Simon Allardice Hailing From Shores Abroad
</a>
</Card.TextLink>
]}
metadata2={[
'Only about the Best Level in the World for Learning',
'2h 20m or longer depending',
"July 24, 1847 or year thereabouts, it's unclear"
]}
title={<Card.Title>Super-long Metadata</Card.Title>}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
</div>
)
}
export default Example

Action bar

The action bar contains the on-card affordances a user can take besides linking straight to the content. These are usually buttons.

Action bar locked visible
import Card from '@pluralsight/ps-design-system-card'
import { BookmarkIcon, MoreIcon } from '@pluralsight/ps-design-system-icon'
import React from 'react'
function Example() {
return (
<div style={{ width: '320px' }}>
<Card
actionBar={[
<Card.Action title="Bookmark action" icon={<BookmarkIcon />} />,
<Card.Action title="More action" icon={<MoreIcon />} />
]}
actionBarVisible
title={<Card.Title>Action bar locked visible</Card.Title>}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
)
}
export default Example

Tag

The tag provides a label, usually categorizing the card's content.

Channel
Icon and text on card
import Card from '@pluralsight/ps-design-system-card'
import { ChannelIcon } from '@pluralsight/ps-design-system-icon'
import React from 'react'
function Example() {
return (
<div style={{ width: '320px' }}>
<Card
tag={<Card.Tag icon={<ChannelIcon />}>Channel</Card.Tag>}
title={<Card.Title>Icon and text on card</Card.Title>}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
)
}
export default Example

Full overlay

A special main action representing the main interaction for the card can be provided here. It will appear overlaid in the center of the image.

Combined with other overlays
import Card from '@pluralsight/ps-design-system-card'
import { BookmarkIcon, ChannelIcon } from '@pluralsight/ps-design-system-icon'
import React from 'react'
function Example() {
return (
<div style={{ width: '320px' }}>
<Card
fullOverlay={
<Card.FullOverlayLink>
<a>Custom Thing</a>
</Card.FullOverlayLink>
}
actionBar={[
<Card.Action title="Bookmark action" icon={<BookmarkIcon />} />
]}
tag={<Card.Tag icon={<ChannelIcon />}>Channel</Card.Tag>}
title={<Card.Title>Combined with other overlays</Card.Title>}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
)
}
export default Example

Bonus bar

Some cards may make use of a freeform area of content overlaid in the bottom-left corner of the image area. Use with dignity.

Just bonus
Custom elements in lower-left
import Card from '@pluralsight/ps-design-system-card'
import React from 'react'
function Example() {
return (
<div style={{ width: '320px' }}>
<Card
bonusBar={<div>Just bonus</div>}
title={<Card.Title>Custom elements in lower-left</Card.Title>}
image={<Card.Image src="https://picsum.photos/seed/picsum/540/360" aria-label="img desc" />}
/>
</div>
)
}
export default Example

Accessibility

WCAG 2.1 AA Compliance

100% axe-core tests
Manual audit

Props

Card

Name
Type
Description
Default
actionBarCard.Action[]top-right action buttons
actionBarVisiblebooleanlock action bar onfalse
bonusBarReact.ReactNodefreeform space in image bottom-left
fullOverlayCard.FullOverlayLinkhover state for image
fullOverlayVisiblebooleanlock full overlay onfalse
image
Required
Card.Image | Card.ImageLink > a > Card.Imagemain image or linked image
metadata1string[] | React.ReactNode[]first row of metadata
metadata2string[] | React.ReactNode[]second row of metadata
progressnumberprogress 0-100
size
small | medium | large
size of card (from Card.sizes)medium
tagCard.Tagcategorization label in top-left
title
Required
Card.TextLink > a > Card.Title | Card.Titlecard title or linked title

Card.Action

Name
Type
Description
Default
icon
Required
Iconicon representing action
title
Required

Card.Image

Name
Type
Description
Default
aria-labelstringscreenreader label
src
Required
stringimage url

Card.Tag

Name
Type
Description
Default
iconIcontag icon