Skip to main content

Card

A self-contained content surface. All cards support a white (default) or transparent surface property.

Polymorphic Component

By default, content is rendered inside a <div>, but this can be overriden by passing any valid tag name or component with the as prop.

Examples

Media Card

A card for highlighting an image, some content, and associated labels/tags. Any child content will be placed after the title, but before the meta and tags.

Title goes here

Reprehenderit in labore id in ad ullamco nisi reprehenderit ex voluptate tempor.

5 min read
Tags

Title goes here

Adipisicing esse velit pariatur commodo exercitation do esse laboris consequat anim in ea. Consequat velit tempor fugiat dolor excepteur id dolore sunt commodo dolore mollit do laborum. Lorem laborum excepteur duis quis minim qui tempor velit id id.

Dolore est excepteur qui dolor ipsum occaecat officia anim Lorem pariatur et et mollit ad. Incididunt nostrud excepteur eiusmod excepteur esse. Velit sint nulla proident occaecat est consequat reprehenderit Lorem enim aliquip.

5 min read
Tags
import { CardImage } from '@curology/ui-components-web/react/Card/CardImage';
import { CardMeta } from '@curology/ui-components-web/react/Card/CardMeta';
import { CardTags } from '@curology/ui-components-web/react/Card/CardTags';
import { Label } from '@curology/ui-components-web/react/Label';
import { MediaCard } from '@curology/ui-components-web/react/Card/MediaCard';
import { MediaCardContent } from '@curology/ui-components-web/react/Card/MediaCard/MediaCardContent';
import { Tag } from '@curology/ui-components-web/react/Tag';

<MediaCard>
<MediaCardContent
label={<Label>Default</Label>}
title="Title goes here"
image={
<CardImage
aspectRatio="3:4"
label={<Label>Default</Label>}
src={exampleImage}
/>
}
tags={
<CardTags title="Tags">
<Tag>Meta tag</Tag>
<Tag>Meta tag</Tag>
</CardTags>
}
meta={<MediaCardMeta>5 min read</MediaCardMeta>}
>
Body copy goes here
</MediaCardContent>
</MediaCard>

Before & After Card

A card specifically for comparing two images. Supports a rating prop. Any child content will be placed after the rating, but before the tags.

Title goes here

Some meta
4.25/5
(12,345)

Reprehenderit in labore id in ad ullamco nisi reprehenderit ex voluptate tempor.

Title goes here

Some meta
3.5/5
(12,345)

Adipisicing esse velit pariatur commodo exercitation do esse laboris consequat anim in ea. Consequat velit tempor fugiat dolor excepteur id dolore sunt commodo dolore mollit do laborum. Lorem laborum excepteur duis quis minim qui tempor velit id id.

import { BeforeAfterCard } from '@curology/ui-components-web/react/Card/BeforeAfterCard';
import { BeforeAfterCardContent } from '@curology/ui-components-web/react/Card/BeforeAfterCard/BeforeAfterCardContent';
import { BeforeAfterCardImages } from '@curology/ui-components-web/react/Card/BeforeAfterCard/BeforeAfterCardImages';
import { CardMeta } from '@curology/ui-components-web/react/Card/CardMeta';
import { CardTags } from '@curology/ui-components-web/react/Card/CardTags';
import { Label } from '@curology/ui-components-web/react/Label';
import { Tag } from '@curology/ui-components-web/react/Tag';

<BeforeAfterCard>
<BeforeAfterCardContent
title="Title goes here"
images={
<BeforeAfterCardImages
beforeProps={{
src: exampleImage,
}}
afterProps={{
src: exampleImage,
}}
/>
}
rating={<CardRating readOnly count="12,345" value="4.25" />}
tags={
<CardTags>
<Tag>Meta tag</Tag>
<Tag>Meta tag</Tag>
</CardTags>
}
meta={<BeforeAfterCardMeta>Some meta</BeforeAfterCardMeta>}
>
Body copy goes here
</BeforeAfterCardContent>
</BeforeAfterCard>

Control Card

A card to use as part of a form flow, like product or option selection. Any child content will be placed after the meta.

When the fullyClickable property is passed to ControlCardContent, clicking anywhere on the card will toggle the checkbox. Do not use this flag if there are additional controls inside the card.

The ControlCard should not be used with surface="transparent".

Headline

$0.00
/mo
$0.00
/mo
Some additional copy

Ad irure id laboris laborum Lorem sunt velit consequat. Lorem eiusmod ullamco velit mollit esse ex qui enim nostrud commodo non exercitation. Culpa consequat eiusmod voluptate pariatur. Adipisicing eiusmod dolore laboris laborum anim incididunt. Laboris reprehenderit anim sint consectetur deserunt ullamco Lorem dolor cillum commodo irure pariatur ad in. Veniam reprehenderit cupidatat laboris tempor et dolore non voluptate qui occaecat nulla dolore do ex.

Select moisturizer

  • The Custom Cleanserᴿˣ
  • The Custom Formulaᴿˣ
  • The moisturizer
import { CardFooter } from '@curology/ui-components-web/react/Card/CardFooter';
import { CardImage } from '@curology/ui-components-web/react/Card/CardImage';
import { CardPricing } from '@curology/ui-components-web/react/Card/CardPricing';
import { ControlCardCard } from '@curology/ui-components-web/react/Card/ControlCardCard';
import { ControlCardCardContent } from '@curology/ui-components-web/react/Card/ControlCardCard/ControlCardCardContent';
import { ControlCardCardRadioButton } from '@curology/ui-components-web/react/Card/ControlCardCard/ControlCardCardRadioButton';
import { ControlCardCardRadioButtonGroup } from '@curology/ui-components-web/react/Card/ControlCardCard/ControlCardCardRadioButtonGroup';
import { Label } from '@curology/ui-components-web/react/Label';
import { List } from '@curology/ui-components-web/react/List';
import { NumberInput } from '@curology/ui-components-web/react/NumberInput';

<ControlCard className="cur-w-1/2">
<ControlCardContent
fullyClickable
input={<Checkbox />}
label={<Label>Label</Label>}
title="Headline"
image={<ControlCardImage aspectRatio="3:4" src={exampleImage} />}
meta={
<>
<CardPricing price="$0.00" salePrice="$0.00" subscription="mo" />
<Typography size="meta">Some additional copy</Typography>
</>
}
rating={<CardRating readOnly count="12,345" value="4.25" />}
>
<Typography size="meta" className="cur-text-subtle">
Ad irure id laboris laborum Lorem sunt velit consequat. Lorem eiusmod
ullamco velit mollit esse ex qui enim nostrud commodo non
exercitation. Culpa consequat eiusmod voluptate pariatur. Adipisicing
eiusmod dolore laboris laborum anim incididunt. Laboris reprehenderit
anim sint consectetur deserunt ullamco Lorem dolor cillum commodo
irure pariatur ad in. Veniam reprehenderit cupidatat laboris tempor et
dolore non voluptate qui occaecat nulla dolore do ex.
</Typography>
<Highlight state="success" icon={<PlaceholderIcon />}>
Highlight
</Highlight>
</ControlCardContent>
</ControlCard>

Product Card

A detailed product description with a clear call to action at the bottom. Any child content will be placed after the rating.

Headline

Some additional copy
$0.00
/mo
$0.00
/mo
4.2/5
(3,215)

Ad irure id laboris laborum Lorem sunt velit consequat. Lorem eiusmod ullamco velit mollit esse ex qui enim nostrud commodo non exercitation.

Ingredients

  • The Custom Cleanserᴿˣ

    Helps smooth texture and fine lines while brightening skin

    0.0005%
  • The Custom Formulaᴿˣ

    Helps smooth texture and fine lines while brightening skin

    0.0005%
  • The moisturizer

    Helps smooth texture and fine lines while brightening skin

    0.0005%

Headline

Some additional copy
$0.00
/mo
$0.00
/mo
4.2/5
(3,215)

Ad irure id laboris laborum Lorem sunt velit consequat. Lorem eiusmod ullamco velit mollit esse ex qui enim nostrud commodo non exercitation.

Ingredients

  • The Custom Cleanserᴿˣ

    Helps smooth texture and fine lines while brightening skin

    0.0005%
  • The Custom Formulaᴿˣ

    Helps smooth texture and fine lines while brightening skin

    0.0005%
  • The moisturizer

    Helps smooth texture and fine lines while brightening skin

    0.0005%
import { Button } from '@curology/ui-components-web/react/Button';
import { CardFooter } from '@curology/ui-components-web/react/Card/CardFooter';
import { CardPricing } from '@curology/ui-components-web/react/Card/CardPricing';
import { CardRating } from '@curology/ui-components-web/react/Card/CardRating';
import { Highlight } from '@curology/ui-components-web/react/Highlight';
import { List } from '@curology/ui-components-web/react/List';
import { ListHeader } from '@curology/ui-components-web/react/ListHeader';
import { ListItem } from '@curology/ui-components-web/react/List/ListItem';
import { ProductCard } from '@curology/ui-components-web/react/Card/ProductCard';
import { ProductCardContent } from '@curology/ui-components-web/react/Card/ProductCard/ProductCardContent';
import { ProductCardImage } from '@curology/ui-components-web/react/Card/ProductCard/ProductCardImage';
import { Typography } from '@curology/ui-components-web/react/Typography';

<ProductCard className="cur-w-1/2">
<ProductCardContent
title="Headline"
image={
<ProductCardImage
aspectRatio="3:4"
label={<Label>Label</Label>}
src={exampleImage}
/>
}
meta={
<>
<Typography size="meta">Some additional copy</Typography>
<CardPricing price="$0.00" salePrice="$0.00" subscription="mo" />
</>
}
rating={<CardRating value={4.2} count={3215} />}
>
<Typography className="cur-text-subtle">
Ad irure id laboris laborum Lorem sunt velit consequat. Lorem eiusmod
ullamco velit mollit esse ex qui enim nostrud commodo non
exercitation.
</Typography>
<ListHeader headerTitle="Ingredients" />
<List className="cur-flex-1" size="xl">
<ListItem
titleEnd="0.0005%"
title="The Custom Cleanserᴿˣ"
iconEnd={<PlaceholderIcon />}
>
Helps smooth texture and fine lines while brightening skin
</ListItem>
<ListItem
titleEnd="0.0005%"
title="The Custom Formulaᴿˣ"
iconEnd={<PlaceholderIcon />}
>
Helps smooth texture and fine lines while brightening skin
</ListItem>
<ListItem
titleEnd="0.0005%"
title="The moisturizer"
iconEnd={<PlaceholderIcon />}
>
Helps smooth texture and fine lines while brightening skin
</ListItem>
</List>
<Highlight state="success" icon={<PlaceholderIcon />}>
Highlight
</Highlight>
<CardFooter>
<Button>Default</Button>
</CardFooter>
</ProductCardContent>
</ProductCard>

Text Card

A text-only card. Any child content will be placed after the title.

Small Text

Esse aute adipisicing irure ea labore reprehenderit nostrud.

Some additional copy
$0.00
/mo
$0.00
/mo
Tags

Medium Text

Esse aute adipisicing irure ea labore reprehenderit nostrud.

Some additional copy
$0.00
/mo
$0.00
/mo
Tags

Large Text

Esse aute adipisicing irure ea labore reprehenderit nostrud.

Some additional copy
$0.00
/mo
$0.00
/mo
Tags
import { Accordion } from '@curology/ui-components-web/react/Accordion';
import { AccordionContent } from '@curology/ui-components-web/react/Accordion/AccordionContent';
import { AccordionSummary } from '@curology/ui-components-web/react/Accordion/AccordionSummary';
import { Button } from '@curology/ui-components-web/react/Button';
import { CardFooter } from '@curology/ui-components-web/react/Card/CardFooter';
import { Label } from '@curology/ui-components-web/react/Label';
import { Tag } from '@curology/ui-components-web/react/Tag';
import { TextCard } from '@curology/ui-components-web/react/Card/TextCard';
import { TextCardContent } from '@curology/ui-components-web/react/Card/TextCard/TextCardContent';
import { TextCardLabels } from '@curology/ui-components-web/react/Card/TextCard/TextCardLabels';
import { TextCardMeta } from '@curology/ui-components-web/react/Card/TextCard/TextCardMeta';
import { TextCardPricing } from '@curology/ui-components-web/react/Card/TextCard/TextCardPricing';
import { TextCardTags } from '@curology/ui-components-web/react/Card/TextCard/TextCardTags';
import { Typography } from '@curology/ui-components-web/react/Typography';

<TextCard size="sm|md (default)|lg" className="cur-w-[38rem] cur-mb-4">
<TextCardContent title="Medium Text">
<Typography size="body-lg">
Esse aute adipisicing irure ea labore reprehenderit nostrud.
</Typography>
<TextCardMeta>
<Typography size="meta">Some additional copy</Typography>
</TextCardMeta>
<TextCardPricing price="$0.00" salePrice="$0.00" subscription="mo" />
<TextCardLabels>
<Label size="lg">Label</Label>
<Label size="lg">Label</Label>
<Label size="lg">Label</Label>
<Label size="lg">Label</Label>
</TextCardLabels>
<div className="cur-mt-12 cur-mb-6">
<Accordion>
<AccordionSummary>Accordion</AccordionSummary>
<AccordionContent>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
sapien enim, rutrum quis tristique ut, ultrices vitae nibh. Sed
feugiat orci vel hendrerit accumsan
</AccordionContent>
</Accordion>
<Accordion>
<AccordionSummary>Accordion</AccordionSummary>
<AccordionContent>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
sapien enim, rutrum quis tristique ut, ultrices vitae nibh. Sed
feugiat orci vel hendrerit accumsan
</AccordionContent>
</Accordion>
<Accordion>
<AccordionSummary>Accordion</AccordionSummary>
<AccordionContent>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
sapien enim, rutrum quis tristique ut, ultrices vitae nibh. Sed
feugiat orci vel hendrerit accumsan
</AccordionContent>
</Accordion>
</div>
<TextCardTags title="Tags">
<Tag>Meta tag</Tag>
<Tag>Meta tag</Tag>
</TextCardTags>
<CardFooter>
<Button>Default</Button>
</CardFooter>
</TextCardContent>
</TextCard>

Basic Card Building Blocks

Custom card layouts can be composed using the various card components together.

Just a white box!
import { Card } from '@curology/ui-components-web/react/Card';

<Card>
Just a white box!
</Card>

Now we're talkin'!

Pretty cool that the footer of the other card sticks to the bottom even though it's shorter...

import { Button } from '@curology/ui-components-web/react/Button';
import { Card } from '@curology/ui-components-web/react/Card';
import { CardContent } from '@curology/ui-components-web/react/Card/CardContent';
import { CardFooter } from '@curology/ui-components-web/react/Card/CardFooter';
import { CardImage } from '@curology/ui-components-web/react/Card/CardImage';

<Card>
<CardContent
image={<CardImage label={<Label>Default</Label>} src={exampleImage} />}
>
Now we're talkin'!
</CardContent>
<CardFooter>
<Button className="cur-w-full">CTA</Button>
<Button className="cur-w-full" buttonType="secondary">
CTA <ButtonMeta>Secondary</ButtonMeta>
</Button>
</CardFooter>
</Card>

Tempor pariatur ut minim nulla proident dolor proident quis magna est deserunt dolore. Eu nulla dolor labore quis mollit fugiat cillum ullamco deserunt ea anim ex cupidatat.

import { Card } from '@curology/ui-components-web/react';
<Card
surface="transparent"
>
...
</Card>

Props

CardProps

NameTypeDefault ValueRequiredDescription
idstring''NoA unique ID for this card.
surface"white" | "transparent"'white'NoThe surface color

CardContentProps

NameTypeDefault ValueRequiredDescription
imageReactElement<any, string | JSXElementConstructor<any>>NoAn (optional) image to display to display at the top (or side) or the card.

CardImageProps

NameTypeDefault ValueRequiredDescription
aspectRatio"auto" | "square" | "1:1" | "2:3" | "3:2" | "3:4" | "4:3" | "4:5" | "5:4"'square'NoConstrain the image to a specific aspect ratio.
labelReactNodeNoA label to overlay on the header content.
labelAlign"left" | "right"'left'NoWhich side should the label be aligned to?

CardPricingProps

NameTypeDefault ValueRequiredDescription
pricestring | numberYesThe price of the product.
salePricestring | numberNoThe sale price of the product.
salePriceSubscriptionstringNoA sale-specific subscription string. If `undefined`, will default to `subscription`. If an empty string, will be blank.
subscriptionstringNoA string to prepend to the prices like "mo" for "$12/mo".

CardRatingProps

NameTypeDefault ValueRequiredDescription
countstring | numberNoA number to display next to the rating.
defaultValuestring | numberNoThe default value of the rating.
onChangeFormControlChangeEventHandlerNoEmit a new value when the input's selected value changes.
readOnlyfalse | truefalseNoCan the field be interacted with?
showCountfalse | trueNo
size"md" | "sm"'md'NoThe size of the field.
valuestring | numberNoThe current value of the rating.

BeforeAfterCardProps

NameTypeDefault ValueRequiredDescription
idstring''NoA unique ID for this card.
surface"white" | "transparent"'white'NoThe surface color

BeforeAfterCardContentProps

NameTypeDefault ValueRequiredDescription
imagesReactElement<any, string | JSXElementConstructor<any>>YesA set of images to display side-by-side.
metaReactNodeNoA bit of text to render below the title and before the content.
ratingReactElement<any, string | JSXElementConstructor<any>>NoA star-based rating.
tagsReactElement<any, string | JSXElementConstructor<any>>NoA tag, or list of tags, to be rendered stuck to the bottom of the card.
titleReactNodeNoText (or a component with text) to be rendered in bold.

BeforeAfterCardImagesProps

NameTypeDefault ValueRequiredDescription
afterPropsOmit<CardImageProps, "aspectRatio">NoAny props to apply to the after image.
aspectRatio"auto" | "square" | "1:1" | "2:3" | "3:2" | "3:4" | "4:3" | "4:5" | "5:4"'3:4'NoAn aspect ratio to enforce on the images.
beforePropsOmit<CardImageProps, "aspectRatio">NoAny props to apply to the after image.

ControlCardProps

NameTypeDefault ValueRequiredDescription
idstring''NoA unique ID for this card.
surface"white" | "transparent"'white'NoThe surface color

ControlCardContentProps

NameTypeDefault ValueRequiredDescription
fullyClickablefalse | truefalseNoShould the full card be clickable?
imageReactElement<any, string | JSXElementConstructor<any>>NoAn (optional) image to display to display at the top (or side) or the card.
inputReactNodeNoThe input to render.
labelReactNodeNoLabel to render at the top of the card, above the title.
metaReactNodeNoA bit of text to render after the title.
ratingReactElement<any, string | JSXElementConstructor<any>>NoA star-based rating.

ControlCardImageProps

NameTypeDefault ValueRequiredDescription
aspectRatio"auto" | "square" | "1:1" | "2:3" | "3:2" | "3:4" | "4:3" | "4:5" | "5:4"'square'NoConstrain the image to a specific aspect ratio.
labelReactNodeNoA label to overlay on the header content.
labelAlign"left" | "right"'left'NoWhich side should the label be aligned to?

ControlCardRadioButtonProps

NameTypeDefault ValueRequiredDescription
alwaysShowChildrenfalse | truefalseNoShould the children display even if `checked=false`?
indeterminatefalse | truefalseNoShow a partially selected checkbox when `checked=true`.
labelReactNodeNoA string or component to display as a label above the input
metaReactNodeNoA string or component to display as meta text beneath the input
onChangeFormControlChangeEventHandlerNoEmit a new value when the input's selected value changes.
recommendedfalse | trueNoRender recommended label along with radio button item
size"md" | "sm"'md'NoThe size of the field
state"" | "critical" | "warning" | "success"''NoThe state of the field

ControlCardRadioButtonGroupProps

NameTypeDefault ValueRequiredDescription
brand"agency" | "curology"''NoThe brand of the component.
defaultValuestring | number | readonly string[] | (string | number | readonly string[] | undefined)[]NoDefault value to use the first time the context is created.
disabledfalse | truefalseNoShould the field be considered disabled?
fieldClassNamestringNoA className to apply to the field.
fieldPropsRecord<string, unknown>NoAny props to spread onto the field container.
helperTextReactNodeNoA string or component to display as helper text beneath the input
highlightReactNodeNoHighlighted helper text to display at the bottom of the multiline text input
highlightClassNamestringNoA className to apply to the highlight.
idstring''NoA unique ID for this form control.
labelReactNodeNoA string or component to display as a label above the input
namestring''NoThe name for the radio group.
onChangeFormControlChangeEventHandler<InputType, string | number | readonly string[] | (string | number | readonly string[] | undefined)[] | undefined> & ((evt: ChangeEvent<...>, value: string | ... 2 more ... | undefined) => void)NoEmit a new value when the input's selected value changes. Emit a new value when the group's selected values change.
requiredfalse | truefalseNoIs the field required?
resizefalse | truefalseNoEnable or disable resizing.
size"md" | "sm"'md'NoThe size of the field.
state"" | "critical" | "warning" | "success"''NoThe state of the field
type"number" | "image" | "search" | "button" | "time" | "text" | "color" | "hidden" | string & {} | "submit" | "reset" | "checkbox" | "date" | "datetime-local" | "email" | "file" | "month" | "password" | "radio" | "range" | "tel" | "url" | "week"'text'NoThe type of the input.
valuestring | number | readonly string[] | string & readonly string[] | number & readonly string[] | readonly string[] & string | readonly string[] & number | (string | number | readonly string[] | undefined)[] & string | (string | number | readonly string[] | undefined)[] & number | (string | number | readonly string[] | undefined)[] & readonly string[]''NoThe currently selected value.

MediaCardProps

NameTypeDefault ValueRequiredDescription
idstring''NoA unique ID for this card.
surface"white" | "transparent"'white'NoThe surface color

MediaCardContentProps

NameTypeDefault ValueRequiredDescription
imageReactElement<any, string | JSXElementConstructor<any>>NoAn (optional) image to display to display at the top (or side) or the card.
labelReactElement<any, string | JSXElementConstructor<any>>NoA label, or list of labels, to be rendered below the image.
metaReactNodeNoA bit of text to render below the title and before the content.
tagsReactElement<any, string | JSXElementConstructor<any>>NoA tag, or list of tags, to be rendered stuck to the bottom of the card.

ProductCardProps

NameTypeDefault ValueRequiredDescription
idstring''NoA unique ID for this card.
surface"white" | "transparent"'white'NoThe surface color

ProductCardContentProps

NameTypeDefault ValueRequiredDescription
horizontalfalse | trueNoDisplays horizontal card styling.
imageReactElement<any, string | JSXElementConstructor<any>>NoAn (optional) image to display to display at the top (or side) or the card.
metaReactNodeNoA bit of text to render after the title.
ratingReactElement<any, string | JSXElementConstructor<any>>NoA star-based rating.
titleReactNodeNoText (or a component with text) to be rendered in bold.

ProductCardImageProps

NameTypeDefault ValueRequiredDescription
aspectRatio"auto" | "square" | "1:1" | "2:3" | "3:2" | "3:4" | "4:3" | "4:5" | "5:4"'square'NoConstrain the image to a specific aspect ratio.
labelReactNodeNoA label to overlay on the header content.
labelAlign"left" | "right"'left'NoWhich side should the label be aligned to?