Recipes
Card as a link
Use this Card when you want the Card itself to link to different places.
function CardAsLinkExample() { return ( <Card role="link" href="https://seeds.sproutsocial.com/" > <Box display="flex" justifyContent="center" alignItems="center" my={400}> <SpotIllustration height="200px" name="calendar-reporting" aria-hidden /> </Box> <Text.SmallByline>Reporting</Text.SmallByline> <CardLink affordance>Visit calendar report</CardLink> </Card> ); }
Card Link
Be sure to wrap the link text that you want to be read to assistive technologies in CardLink. This subcomponent receives the href via context from the parent and handles all default link behavior while allowing the Card itself to act as the click target. The Card as a link will not work properly without this component.
CardLink takes an optional affordance prop that makes adding a little extra oomph to links extra easy.
Card as a button
Use this Card when you need a region of content to perform a specific action. We should avoid nesting interactive elements inside Cards when they are used as a button.
function CardAsButtonExample() { const [message, setMessage] = React.useState(false); const _onClick = () => { setMessage(true); }; React.useEffect(() => { const showMessage = setTimeout(() => { setMessage(false); }, 4000); return function cleanup() { clearTimeout(showMessage); }; }, [message]); return ( <> {message ? ( <Box mb={400}> <Banner text="Your click was successful." /> </Box> ) : ( <Box mb={400}> <Banner type="warning" text={ <Box width={1} display="flex" alignItems="center" justifyContent="space-between" > <Text width={3/4}> Avoid nesting interactive content inside a Card with role='button' </Text> </Box> } /> </Box> )} <Card role='button' onClick={_onClick}> <Box mx="auto" mb={400}> <SpotIllustration height="200px" name="coffee-cup" aria-hidden /> </Box> <Text.SmallByline>SEEDS WEB</Text.SmallByline> <Text.Headline mb={300}>Card component</Text.Headline> <Text.BodyCopy> The card component is a styled primitive container. </Text.BodyCopy> </Card> </> ); }
Card for presentation
Use this Card when you need a simple way to display a region of related content.
While these Cards do have an optional onClick, it should only be leveraged for non-user facing actions like pollinator events or other data collection. While the Card may contain an interactive element, the Card itself should never take action via the user.
function CardForPresentationExample() { return ( <Card role='presentation'> <Text.SmallByline>SEEDS WEB</Text.SmallByline> <Text.Headline mb={300}>Card component</Text.Headline> <Box mx="auto" my={400}> <SpotIllustration height="200px" name="coffee-cup" aria-hidden /> </Box> <Text.BodyCopy mb={400}> The card component is a styled primitive container. </Text.BodyCopy> <Link fontSize={300} href="https://google.com/" external> Use now <Icon mb={100} ml={300} size="mini" name="arrow-right-solid" role={undefined} svgProps={{role: 'img', 'aria-label': 'opens in a new tab'}} /> </Link> </Card> ); }
Disabled Card
Cards can also be disabled via the disabled prop. This disabled state leverages the Seeds disabled mixin.
function DisabledCardExample() { const [message, setMessage] = React.useState(false); const _onClick = () => { setMessage(true); }; React.useEffect(() => { const showMessage = setTimeout(() => { setMessage(false); }, 4000); return function cleanup() { clearTimeout(showMessage); }; }, [message]); return ( <> {message ? ( <Box mb={400}> <Banner text="Your click was successful." /> </Box> ) : ( <Box mb={400}> <Banner type="warning" text={ <Box width={1} display="flex" alignItems="center" justifyContent="space-between" > <Text width={3/4}> Avoid nesting interactive content inside a Card with role='button' </Text> </Box> } /> </Box> )} <Card role='button' onClick={_onClick} disabled> <Box mx="auto" mb={400}> <SpotIllustration height="200px" name="coffee-cup" aria-hidden /> </Box> <Text.SmallByline>SEEDS WEB</Text.SmallByline> <Text.Headline mb={300}>Card component</Text.Headline> <Text.BodyCopy> The card component is a styled primitive container. </Text.BodyCopy> </Card> </> ); }
Selectable Card
Cards can be individually selected via the selected prop.
function SelectableCardExample() { const [selectedState, setSelectedState] = React.useState(false); const toggle = () => setSelectedState(!selectedState); return ( <Card onClick={toggle} role='checkbox' selected={selectedState}> <CardContent my={450} mx="auto"> <Icon name="chart-pie-outline" size="jumbo" color="icon.base" aria-hidden /> </CardContent> <CardFooter flexDirection="column"> <Text.SmallSubHeadline>Card Title</Text.SmallSubHeadline> <Text.SmallBodyCopy> This is a card that can be selected. </Text.SmallBodyCopy> </CardFooter> </Card> ); }
List of Cards
When creating a list of Cards, be sure to use a semantic list element.
function ListOfCardsExample() { const cards = [ { subhead: 'Reporting', reportName: 'Profile performance', image: 'reporting', href: 'https://app.sproutsocial.com/reports/group_report', }, { subhead: 'Reporting', reportName: 'Post performance', image: 'reporting-folder', href: 'https://app.sproutsocial.com/reports/post_performance', }, { subhead: 'Reporting', reportName: 'Tag performance', image: 'analytics-offering', href: 'https://app.sproutsocial.com/reports/tag_performance', }, { subhead: 'Reporting', reportName: 'Paid performance', image: 'listening-tour', href: 'https://app.sproutsocial.com/reports/cross_network_campaign_performance', }, ]; const StyledList = styled.ul` list-style: none; display: flex; flex-wrap: wrap; `; return ( <StyledList> {cards.map((card) => { return ( <li> <Card role="link" href={card.href} width="300px" mr={400} mb={400}> <Box display="flex" justifyContent="center" alignItems="center" my={400} > <SpotIllustration height="200px" name={card.image} aria-hidden /> </Box> <Text.SmallByline>{card.subhead}</Text.SmallByline> <CardLink affordance>Visit {card.reportName} report</CardLink> </Card> </li> ); })} </StyledList> ); }
Complex Card
Three subcomponents are available to make composing complex layouts with Card easy.
<CardHeader /><CardContent /><CardFooter />
Simply drop elements into these subcomponent and the Card will handle the padding and layout for you. Card subcomponents can still utilize system props for overrides when necessary.
function ComplexCardExample() { return ( <Card role="presentation"> <CardHeader> <Avatar appearance="leaf" size="24px" name="Card Header" /> <Text.SubHeadline ml={300}>This is a card header</Text.SubHeadline> </CardHeader> <CardContent> <Text.SmallBodyCopy as="p"> We can use the CardContent component to render cool content as seen here: </Text.SmallBodyCopy> </CardContent> <CardFooter> <Link external href="https://google.com"> <Box display="flex" alignItems="center"> Action in CardFooter <Icon ml={200} name="arrow-right-up-outline" role={undefined} svgProps={{role: 'img', 'aria-label': 'opens in a new tab'}} /> </Box> </Link> </CardFooter> </Card> ); }