Skip to main contentSkip to docs navigation

Flexible content container with image, header, footer, and layout options, plus contextual background colors.

Overview

A <Card> is a flexible content container built with flexbox, composing options for images, headers, footers, and a wide variety of body content. A card has no top, left, or right margin by default — spacing utilities apply as needed — and no fixed width to start, so it fills the full width of its parent.

Basic usage

A basic card mixes an image, a title, body text, and a button inside a fixed width.

Card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Go somewhere
JSX
import { Button, Card, CardBody, CardImage, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card style={{ width: '18rem' }}>
      <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
      <CardBody>
        <CardTitle>Card title</CardTitle>
        <CardText>
          Some quick example text to build on the card title and make up the bulk of the card's
          content.
        </CardText>
        <Button href="#">Go somewhere</Button>
      </CardBody>
    </Card>
  )
}

For the common case — a single image, a title, some text, maybe a footer — <Card> accepts image/imageAlt/imageOrientation, title, subtitle, text, and footer shorthand props directly, instead of composing CardImage/CardBody/CardTitle/CardText/CardFooter directly. title/subtitle/text/children render together inside a single CardBody, in that order, so children still works for trailing content like a button. This example produces the same markup as the one above:

Card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Go somewhere
JSX
import { Button, Card } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card
      style={{ width: '18rem' }}
      image="https://placehold.co/800x400"
      title="Card title"
      text="Some quick example text to build on the card title and make up the bulk of the card's content."
    >
      <Button href="#">Go somewhere</Button>
    </Card>
  )
}

Shorthand props only take effect once at least one of image/title/subtitle/text/footer is set — otherwise children render exactly as passed, so full manual composition (CardHeader, flush lists, image overlays, nav headers, horizontal layouts, …) keeps working unchanged. Mixing shorthand props with a manually-composed children tree (e.g. a raw CardHeader) isn't supported — pick one approach per card, falling back to composing CardBody/CardTitle/etc. directly for anything the shorthand props don't cover.

image also accepts a full element instead of a src string — a <CardImage> composed by hand, a <Placeholder>, a loading <Skeleton> — rendered as-is in the image slot, so the rest of title/subtitle/text/footer don't have to give up their shorthand just because the image needs something other than a plain URL. imageAlt/imageOrientation only apply to the src form; set them directly on the passed element otherwise. See Loading states for a worked example swapping the image for a skeleton while data loads.

Content types

<Card> supports a wide variety of content, including images, text, lists, and links.

Body

<CardBody> is the main padded content region of a card.

This is some text within a card body.
JSX
import { Card, CardBody } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card>
      <CardBody>This is some text within a card body.</CardBody>
    </Card>
  )
}

<CardTitle> renders a card's title, and <CardLink> renders links positioned next to each other. <CardSubtitle> renders a subtitle — when both <CardTitle> and <CardSubtitle> sit inside the same <CardBody>, their spacing lines up automatically.

Card title
Card subtitle

Some quick example text to build on the card title and make up the bulk of the card's content.

Card linkAnother link

JSX
import { Card, CardBody, CardLink, CardSubtitle, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card style={{ width: '18rem' }}>
      <CardBody>
        <CardTitle>Card title</CardTitle>
        <CardSubtitle className="mb-md fg-subtle">Card subtitle</CardSubtitle>
        <CardText>
          Some quick example text to build on the card title and make up the bulk of the card's
          content.
        </CardText>
        <CardText>
          <CardLink href="#">Card link</CardLink>
          <CardLink href="#">Another link</CardLink>
        </CardText>
      </CardBody>
    </Card>
  )
}

Images

orientation="top" places an image at the top of the card. <CardText> renders text content, styled with regular HTML tags as needed.

Some quick example text to build on the card title and make up the bulk of the card's content.

JSX
import { Card, CardBody, CardImage, CardText } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card style={{ width: '18rem' }}>
      <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
      <CardBody>
        <CardText>
          Some quick example text to build on the card title and make up the bulk of the card's
          content.
        </CardText>
      </CardBody>
    </Card>
  )
}

<CardImage> renders an <img> by default, but its component prop accepts any element or component — including a framework's own Image (Next.js, Gatsby, Remix, etc.). The passed component is fully type-checked at the call site, so its own props (fill, priority, loader, and so on) are available and validated alongside src/alt:

TSX
import Image from 'next/image'

<CardImage component={Image} src="/hero.jpg" alt="" fill priority orientation="top" />

Lists

A flush <List> renders a list of content inside a card without its own padding.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
JSX
import { Card, List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card style={{ width: '18rem' }}>
      <List flush>
        <ListItem>Cras justo odio</ListItem>
        <ListItem>Dapibus ac facilisis in</ListItem>
        <ListItem>Vestibulum at eros</ListItem>
      </List>
    </Card>
  )
}
Header
  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
JSX
import { Card, CardHeader, List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card style={{ width: '18rem' }}>
      <CardHeader>Header</CardHeader>
      <List flush>
        <ListItem>Cras justo odio</ListItem>
        <ListItem>Dapibus ac facilisis in</ListItem>
        <ListItem>Vestibulum at eros</ListItem>
      </List>
    </Card>
  )
}
  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
JSX
import { Card, CardFooter, List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card style={{ width: '18rem' }}>
      <List flush>
        <ListItem>Cras justo odio</ListItem>
        <ListItem>Dapibus ac facilisis in</ListItem>
        <ListItem>Vestibulum at eros</ListItem>
      </List>
      <CardFooter>Footer</CardFooter>
    </Card>
  )
}

Kitchen sink

Image styles, body content, and a list combine inside a single fixed-width card.

Card title

Some quick example text to build on the card title and make up the bulk of the card's content.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
JSX
import {
  Card,
  CardBody,
  CardImage,
  CardLink,
  CardText,
  CardTitle,
  List,
  ListItem
} from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card style={{ width: '18rem' }}>
      <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
      <CardBody>
        <CardTitle>Card title</CardTitle>
        <CardText>
          Some quick example text to build on the card title and make up the bulk of the card's
          content.
        </CardText>
      </CardBody>
      <List flush>
        <ListItem>Cras justo odio</ListItem>
        <ListItem>Dapibus ac facilisis in</ListItem>
        <ListItem>Vestibulum at eros</ListItem>
      </List>
      <CardBody>
        <CardLink href="#">Card link</CardLink>
        <CardLink href="#">Another link</CardLink>
      </CardBody>
    </Card>
  )
}

<CardHeader> and <CardFooter> add an optional header and/or footer to a card.

Header
Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import { Button, Card, CardBody, CardHeader, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card>
      <CardHeader>Header</CardHeader>
      <CardBody>
        <CardTitle>Special title treatment</CardTitle>
        <CardText>With supporting text below as a natural lead-in to additional content.</CardText>
        <Button href="#">Go somewhere</Button>
      </CardBody>
    </Card>
  )
}

<CardHeader> accepts a component prop — component="h5", for example — to change its rendered element.

Header
Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import { Button, Card, CardBody, CardHeader, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card>
      <CardHeader component="h5">Header</CardHeader>
      <CardBody>
        <CardTitle>Special title treatment</CardTitle>
        <CardText>With supporting text below as a natural lead-in to additional content.</CardText>
        <Button href="#">Go somewhere</Button>
      </CardBody>
    </Card>
  )
}
Quote

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.

Someone famous in Source Title
JSX
import { Card, CardBody, CardHeader } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card>
      <CardHeader>Quote</CardHeader>
      <CardBody>
        <figure className="mb-0">
          <blockquote className="blockquote">
            <p>
              Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.
            </p>
          </blockquote>
          <figcaption className="attribution mb-0">
            Someone famous in <cite title="Source Title">Source Title</cite>
          </figcaption>
        </figure>
      </CardBody>
    </Card>
  )
}
Header
Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import {
  Button,
  Card,
  CardBody,
  CardFooter,
  CardHeader,
  CardText,
  CardTitle
} from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card className="text-center">
      <CardHeader>Header</CardHeader>
      <CardBody>
        <CardTitle>Special title treatment</CardTitle>
        <CardText>With supporting text below as a natural lead-in to additional content.</CardText>
        <Button href="#">Go somewhere</Button>
      </CardBody>
      <CardFooter className="fg-subtle">2 days ago</CardFooter>
    </Card>
  )
}

Sizing

A card has no specific width set by default, so it renders at 100% width unless otherwise stated. The grid, sizing utilities, and custom CSS all adjust this as needed.

Using grid markup

A <Grid> sizes cards by the columns its items span.

Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import { Button, Card, CardBody, CardText, CardTitle, Grid, GridItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Grid gap="md">
      <GridItem span={{ base: 'full', sm: 6 }}>
        <Card>
          <CardBody>
            <CardTitle>Special title treatment</CardTitle>
            <CardText>
              With supporting text below as a natural lead-in to additional content.
            </CardText>
            <Button href="#">Go somewhere</Button>
          </CardBody>
        </Card>
      </GridItem>
      <GridItem span={{ base: 'full', sm: 6 }}>
        <Card>
          <CardBody>
            <CardTitle>Special title treatment</CardTitle>
            <CardText>
              With supporting text below as a natural lead-in to additional content.
            </CardText>
            <Button href="#">Go somewhere</Button>
          </CardBody>
        </Card>
      </GridItem>
    </Grid>
  )
}

Using utilities

Sizing utilities set a card's width directly.

Card title

With supporting text below as a natural lead-in to additional content.

Go somewhere
Card title

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import { Button, Card, CardBody, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Card className="w-75">
        <CardBody>
          <CardTitle>Card title</CardTitle>
          <CardText>
            With supporting text below as a natural lead-in to additional content.
          </CardText>
          <Button href="#">Go somewhere</Button>
        </CardBody>
      </Card>
      <Card className="w-50">
        <CardBody>
          <CardTitle>Card title</CardTitle>
          <CardText>
            With supporting text below as a natural lead-in to additional content.
          </CardText>
          <Button href="#">Go somewhere</Button>
        </CardBody>
      </Card>
    </>
  )
}

Using custom CSS

Custom CSS in a stylesheet or as an inline style also sets a card's width.

Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import { Button, Card, CardBody, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card style={{ width: '18rem' }}>
      <CardBody>
        <CardTitle>Special title treatment</CardTitle>
        <CardText>With supporting text below as a natural lead-in to additional content.</CardText>
        <Button href="#">Go somewhere</Button>
      </CardBody>
    </Card>
  )
}

Text alignment

Text align classes change the text arrangement of a card, in whole or in specific parts.

Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import { Button, Card, CardBody, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Card style={{ width: '18rem' }}>
        <CardBody>
          <CardTitle>Special title treatment</CardTitle>
          <CardText>
            With supporting text below as a natural lead-in to additional content.
          </CardText>
          <Button href="#">Go somewhere</Button>
        </CardBody>
      </Card>
      <Card className="text-center" style={{ width: '18rem' }}>
        <CardBody>
          <CardTitle>Special title treatment</CardTitle>
          <CardText>
            With supporting text below as a natural lead-in to additional content.
          </CardText>
          <Button href="#">Go somewhere</Button>
        </CardBody>
      </Card>
      <Card className="text-end" style={{ width: '18rem' }}>
        <CardBody>
          <CardTitle>Special title treatment</CardTitle>
          <CardText>
            With supporting text below as a natural lead-in to additional content.
          </CardText>
          <Button href="#">Go somewhere</Button>
        </CardBody>
      </Card>
    </>
  )
}

A <Nav> composed inside <CardHeader> adds navigation to a card.

Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import {
  Button,
  Card,
  CardBody,
  CardHeader,
  CardText,
  CardTitle,
  Nav,
  NavItem,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card className="text-center">
      <CardHeader>
        <Nav variant="tabs" className="card-header-tabs">
          <NavItem>
            <NavLink href="#" active>
              Active
            </NavLink>
          </NavItem>
          <NavItem>
            <NavLink href="#">Link</NavLink>
          </NavItem>
          <NavItem>
            <NavLink href="#" disabled>
              Disabled
            </NavLink>
          </NavItem>
        </Nav>
      </CardHeader>
      <CardBody>
        <CardTitle>Special title treatment</CardTitle>
        <CardText>With supporting text below as a natural lead-in to additional content.</CardText>
        <Button href="#">Go somewhere</Button>
      </CardBody>
    </Card>
  )
}
Special title treatment

With supporting text below as a natural lead-in to additional content.

Go somewhere
JSX
import {
  Button,
  Card,
  CardBody,
  CardHeader,
  CardText,
  CardTitle,
  Nav,
  NavItem,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card className="text-center">
      <CardHeader>
        <Nav variant="segments" className="card-header-segments">
          <NavItem>
            <NavLink href="#" active>
              Active
            </NavLink>
          </NavItem>
          <NavItem>
            <NavLink href="#">Link</NavLink>
          </NavItem>
          <NavItem>
            <NavLink href="#" disabled>
              Disabled
            </NavLink>
          </NavItem>
        </Nav>
      </CardHeader>
      <CardBody>
        <CardTitle>Special title treatment</CardTitle>
        <CardText>With supporting text below as a natural lead-in to additional content.</CardText>
        <Button href="#">Go somewhere</Button>
      </CardBody>
    </Card>
  )
}

Images

Beyond a plain image inside a card, images support two more placements: "image caps" at either end of a card, or an overlay behind the card's content.

Image caps

Similar to headers and footers, a card renders top and bottom "image caps" — images at the top or bottom of a card.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Last updated 3 mins ago

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Last updated 3 mins ago

JSX
import { Card, CardBody, CardImage, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Card className="mb-md">
        <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
        <CardBody>
          <CardTitle>Card title</CardTitle>
          <CardText>
            This is a wider card with supporting text below as a natural lead-in to additional
            content. This content is a little bit longer.
          </CardText>
          <CardText>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardText>
        </CardBody>
      </Card>
      <Card className="mb-md">
        <CardBody>
          <CardTitle>Card title</CardTitle>
          <CardText>
            This is a wider card with supporting text below as a natural lead-in to additional
            content. This content is a little bit longer.
          </CardText>
          <CardText>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardText>
        </CardBody>
        <CardImage orientation="bottom" src="https://placehold.co/800x400" alt="" />
      </Card>
    </>
  )
}

Image overlays

An image serves as a background with content overlaid on top of it. Depending on the image, additional styles or utilities may be needed for legibility.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Last updated 3 mins ago

JSX
import { Card, CardImage, CardImageOverlay, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card className="mb-md bg-black fg-white">
      <CardImage src="https://placehold.co/800x400" alt="" />
      <CardImageOverlay>
        <CardTitle>Card title</CardTitle>
        <CardText>
          This is a wider card with supporting text below as a natural lead-in to additional
          content. This content is a little bit longer.
        </CardText>
        <CardText>Last updated 3 mins ago</CardText>
      </CardImageOverlay>
    </Card>
  )
}

Horizontal

Set direction="row" on <Card> to lay it out side-by-side instead of stacked, or an object such as direction={{ lg: 'row' }} for a breakpoint-gated switch. Wrap the image and body in elements with a fraction width (.lg:w-4/12, .lg:w-8/12) to control each side's width, and give <CardImage> orientation={{ base: 'top', lg: 'start' }} so the image's rounded corners switch from the top edge to the start edge at the same breakpoint the card switches to a row. At a breakpoint orientation takes start and end, from sm to xl: top and bottom have a class at base only.

A Tailwind build of @chassis-ui/css has the classes of direction, and of the gap of <CardBody>, only with its safelist loaded: see Tailwind.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Last updated 3 mins ago

JSX
import { Card, CardBody, CardImage, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card direction={{ lg: 'row' }}>
      <div className="lg:w-4/12">
        <CardImage
          orientation={{ base: 'top', lg: 'start' }}
          src="https://placehold.co/800x400"
          alt=""
          style={{ height: '100%', objectFit: 'cover' }}
        />
      </div>
      <div className="lg:w-8/12">
        <CardBody>
          <CardTitle>Card title</CardTitle>
          <CardText>
            This is a wider card with supporting text below as a natural lead-in to additional
            content. This content is a little bit longer.
          </CardText>
          <CardText>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardText>
        </CardBody>
      </div>
    </Card>
  )
}

To place the image inside a padded body region instead of flush against the card edge, apply direction to <CardBody> itself and nest a second <CardBody className="p-0"> for the text side so it doesn't get double padding.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Last updated 3 mins ago

JSX
import { Card, CardBody, CardImage, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Card>
      <CardBody direction={{ lg: 'row' }} gap="md">
        <div className="lg:w-4/12">
          <CardImage src="https://placehold.co/800x400" alt="" />
        </div>
        <div className="lg:w-8/12">
          <CardBody className="p-0">
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
            <CardText className="mb-0">
              <small className="fg-subtle">Last updated 3 mins ago</small>
            </CardText>
          </CardBody>
        </div>
      </CardBody>
    </Card>
  )
}

Card styles

A card supports several options for customizing its backgrounds, borders, and context.

Context colors

Set color to one of the Chassis context colors, and variant to solid, smooth, or outline to control the intensity — omit variant for the default (a tinted border and heading, matching the basic chassis-css style).

Header
primary card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
secondary card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
neutral card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
success card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
danger card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
warning card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
info card title

Some quick example text to build on the card title and make up the bulk of the card's content.

JSX
import { Card, CardBody, CardHeader, CardText, CardTitle } from '@chassis-ui/react'

const COLORS = ['primary', 'secondary', 'neutral', 'success', 'danger', 'warning', 'info'] as const

export const Example = () => {
  return (
    <>
      {COLORS.map((color) => (
        <Card color={color} className="mb-md" style={{ maxWidth: '18rem' }} key={color}>
          <CardHeader>Header</CardHeader>
          <CardBody>
            <CardTitle>{color} card title</CardTitle>
            <CardText>
              Some quick example text to build on the card title and make up the bulk of the card's
              content.
            </CardText>
          </CardBody>
        </Card>
      ))}
    </>
  )
}
Header
solid card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
smooth card title

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
outline card title

Some quick example text to build on the card title and make up the bulk of the card's content.

JSX
import { Card, CardBody, CardHeader, CardText, CardTitle } from '@chassis-ui/react'

const VARIANTS = ['solid', 'smooth', 'outline'] as const

export const Example = () => {
  return (
    <>
      {VARIANTS.map((variant) => (
        <Card
          color="primary"
          variant={variant}
          className="mb-md"
          style={{ maxWidth: '18rem' }}
          key={variant}
        >
          <CardHeader>Header</CardHeader>
          <CardBody>
            <CardTitle>{variant} card title</CardTitle>
            <CardText>
              Some quick example text to build on the card title and make up the bulk of the card's
              content.
            </CardText>
          </CardBody>
        </Card>
      ))}
    </>
  )
}

Using context to add meaning only provides a visual indication, which isn't conveyed to users of assistive technologies such as screen readers. Ensure that information denoted by the context is either obvious from the content itself (e.g. the visible text), or is included through alternative means, such as additional text hidden with the .visually-hidden class.

Utility styling

For finer-grained control than color/variant provides, background, foreground, and border utility classes applied via each sub-component's className target individual regions directly.

Header
Primary background

Some quick example text to build on the card title and make up the bulk of the card's content.

Header
Custom text color

Some quick example text to build on the card title and make up the bulk of the card's content.

JSX
import { Card, CardBody, CardFooter, CardHeader, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Card className="border-primary mb-md" style={{ maxWidth: '18rem' }}>
        <CardHeader className="primary-bg-evident">Header</CardHeader>
        <CardBody className="primary-bg-main">
          <CardTitle>Primary background</CardTitle>
          <CardText>
            Some quick example text to build on the card title and make up the bulk of the card's
            content.
          </CardText>
        </CardBody>
        <CardFooter className="primary-bg-even">Footer</CardFooter>
      </Card>
      <Card style={{ maxWidth: '18rem' }}>
        <CardHeader className="fg-primary border-primary">Header</CardHeader>
        <CardBody className="fg-secondary">
          <CardTitle>Custom text color</CardTitle>
          <CardText>
            Some quick example text to build on the card title and make up the bulk of the card's
            content.
          </CardText>
        </CardBody>
        <CardFooter className="fg-subtle primary-border-main">Footer</CardFooter>
      </Card>
    </>
  )
}

Size variants

Set size to sm or lg to re-scale a card's padding, gaps, and typography together — omit it for the md default.

Card title
Card subtitle

Some quick example text to build on the card title and make up the bulk of the card's content.

Go somewhere
Card title
Card subtitle

Some quick example text to build on the card title and make up the bulk of the card's content.

Go somewhere
JSX
import {
  Button,
  Card,
  CardBody,
  CardImage,
  CardSubtitle,
  CardText,
  CardTitle
} from '@chassis-ui/react'

export const Example = () => {
  return (
    <>
      <Card size="sm" style={{ width: '16rem' }}>
        <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
        <CardBody>
          <CardTitle>Card title</CardTitle>
          <CardSubtitle>Card subtitle</CardSubtitle>
          <CardText>
            Some quick example text to build on the card title and make up the bulk of the card's
            content.
          </CardText>
          <Button href="#" color="primary" className="me-auto">
            Go somewhere
          </Button>
        </CardBody>
      </Card>
      <Card size="lg" style={{ width: '22rem' }}>
        <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
        <CardBody>
          <CardTitle>Card title</CardTitle>
          <CardSubtitle>Card subtitle</CardSubtitle>
          <CardText>
            Some quick example text to build on the card title and make up the bulk of the card's
            content.
          </CardText>
          <Button href="#" color="primary" className="me-auto">
            Go somewhere
          </Button>
        </CardBody>
      </Card>
    </>
  )
}

Card layout

Beyond styling the content within a card, Chassis includes a few options for laying out series of cards.

Card groups

<CardGroup> renders cards as a single, attached element with equal-width and equal-height columns. <CardGroup> uses a container query to switch from stacked to a row once its container reaches the sm container breakpoint, so it must be wrapped in an element carrying .contains-inline to establish that container context.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Last updated 3 mins ago

Card title

This card has supporting text below as a natural lead-in to additional content.

Last updated 3 mins ago

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This card has even longer content than the first to show that equal height action.

Last updated 3 mins ago

JSX
import { Card, CardBody, CardGroup, CardImage, CardText, CardTitle } from '@chassis-ui/react'

export const Example = () => {
  return (
    <div className="contains-inline">
      <CardGroup>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
            <CardText>
              <small className="fg-subtle">Last updated 3 mins ago</small>
            </CardText>
          </CardBody>
        </Card>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This card has supporting text below as a natural lead-in to additional content.
            </CardText>
            <CardText>
              <small className="fg-subtle">Last updated 3 mins ago</small>
            </CardText>
          </CardBody>
        </Card>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This card has even longer content than the first to show that equal height
              action.
            </CardText>
            <CardText>
              <small className="fg-subtle">Last updated 3 mins ago</small>
            </CardText>
          </CardBody>
        </Card>
      </CardGroup>
    </div>
  )
}

Card footers line up automatically within a card group.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This card has supporting text below as a natural lead-in to additional content.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This card has even longer content than the first to show that equal height action.

JSX
import {
  Card,
  CardBody,
  CardFooter,
  CardGroup,
  CardImage,
  CardText,
  CardTitle
} from '@chassis-ui/react'

export const Example = () => {
  return (
    <div className="contains-inline">
      <CardGroup>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This card has supporting text below as a natural lead-in to additional content.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This card has even longer content than the first to show that equal height
              action.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </CardGroup>
    </div>
  )
}

Grid cards

The columns prop of <Grid> controls how many cards share a row, at every width or per breakpoint. columns={{ base: 1, md: 2 }} lays the cards out on one column, and splits four cards into two per row from the md breakpoint up.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

JSX
import { Card, CardBody, CardFooter, CardImage, CardText, CardTitle, Grid } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Grid columns={{ base: 1, md: 2 }} gap="md">
      <div>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
      <div>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
      <div>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
      <div>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
    </Grid>
  )
}

Changing it to columns={{ base: 1, md: 3 }} wraps the fourth card onto a second row.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

JSX
import { Card, CardBody, CardFooter, CardImage, CardText, CardTitle, Grid } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Grid columns={{ base: 1, md: 3 }} gap="md">
      <div>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
      <div>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
      <div>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
      <div>
        <Card>
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
    </Grid>
  )
}

Adding .h-100 to each card gives every card in a row equal height; setting $card-height: 100% in Sass applies equal heights by default.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This card has supporting text below as a natural lead-in to additional content.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This card has even longer content than the first to show that equal height action.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

JSX
import { Card, CardBody, CardImage, CardText, CardTitle, Grid } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Grid columns={{ base: 1, md: 3 }} gap="md">
      <div>
        <Card className="h-100">
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
        </Card>
      </div>
      <div>
        <Card className="h-100">
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This card has supporting text below as a natural lead-in to additional content.
            </CardText>
          </CardBody>
        </Card>
      </div>
      <div>
        <Card className="h-100">
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This card has even longer content than the first to show that equal height
              action.
            </CardText>
          </CardBody>
        </Card>
      </div>
      <div>
        <Card className="h-100">
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
        </Card>
      </div>
    </Grid>
  )
}

Card footers line up automatically within an equal-height row, the same as inside a card group.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.

Card title

This card has supporting text below as a natural lead-in to additional content.

Card title

This is a wider card with supporting text below as a natural lead-in to additional content. This card has even longer content than the first to show that equal height action.

JSX
import { Card, CardBody, CardFooter, CardImage, CardText, CardTitle, Grid } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Grid columns={{ base: 1, md: 3 }} gap="md">
      <div>
        <Card className="h-100">
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This content is a little bit longer.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
      <div>
        <Card className="h-100">
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This card has supporting text below as a natural lead-in to additional content.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
      <div>
        <Card className="h-100">
          <CardImage orientation="top" src="https://placehold.co/800x400" alt="" />
          <CardBody>
            <CardTitle>Card title</CardTitle>
            <CardText>
              This is a wider card with supporting text below as a natural lead-in to additional
              content. This card has even longer content than the first to show that equal height
              action.
            </CardText>
          </CardBody>
          <CardFooter>
            <small className="fg-subtle">Last updated 3 mins ago</small>
          </CardFooter>
        </Card>
      </div>
    </Grid>
  )
}

API

Card

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
color?ContextColor—
Sets the color of the component to one of Chassis context colors.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
direction?Responsive<FlexDirection>—
Switches the card from its default stacked (column) layout to a side-by-side (row) layout. Give the image and the body a width utility (w-4/12, w-8/12) to control each side's width. An object sets the direction from a breakpoint up — e.g. { lg: 'row' } to lay the card out horizontally from lg up while stacking below it.
footer?ReactNode—
Shorthand for a CardFooter, rendered after the image/title/subtitle/text/children block.
image?ReactNode—
Shorthand for a CardImage — pass either a src URL (combine with imageAlt/ imageOrientation) or a fully-formed element — a <CardImage>, <Skeleton>, <Placeholder>, or anything else — rendered as-is in its place. imageAlt/imageOrientation only apply to the src form; set them directly on your own element otherwise. For a horizontal layout or an overlay, omit this and compose CardImage directly as a child instead.
imageAlt?string—
Accessible alt text for image. Ignored unless image is set.
imageOrientation?"top" | "bottom"—
Orientates image to the top (default) or bottom of the card.
ref?any—
size?Sizing—
Sets the size of the component to one of Chassis component sizes.
subtitle?ReactNode—
Shorthand for a CardSubtitle, rendered directly after title.
text?ReactNode—
Shorthand for a CardText, rendered after title/subtitle.
title?ReactNode—
Shorthand for a CardTitle. Set alongside subtitle/text (or plain children, e.g. a Button) to build a standard card without composing CardBody/CardTitle yourself — all render together inside a single CardBody, in that order. Only takes effect when at least one of image/title/subtitle/text/footer is set; otherwise children render as-is, so full manual composition (CardHeader, lists, overlays, nav headers, …) keeps working unchanged. Mixing shorthand props with a manually-composed children tree isn't supported — pick one approach per card.
variant?ContextStyle—
Sets the context style of the component. basic (the default) renders with no extra class.

CardBody

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
direction?Responsive<FlexDirection>—
Switches the body from its default stacked (column) layout to a side-by-side (row) layout — for placing an image beside text within a single padded region. Give the image and the text a width utility (w-4/12, w-8/12) to control each side's width, and nest another CardBody (with .p-0) for the text side so it doesn't receive double padding. An object sets the direction from a breakpoint up: { md: 'row' }.
gap?{ Spacing | 0 }—
Spacing between children, mapped to the gap-* utility classes. Overrides the card's default gap between body children.
ref?any—

CardFooter

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—

CardGroup

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—

CardHeader

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—

CardImage

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component — e.g. a framework's own Image component. Its own props (src, fill, priority, etc.) are type-checked at the call site once passed here.
orientation?Responsive<CardImageOrientation>—
Orientates the image to the top or bottom of the card as an "image cap", or to the start/end for a horizontal layout. Omit to round all four corners for use inside CardBody. An object sets the orientation from a breakpoint up — e.g. { base: 'top', lg: 'start' } to switch an image cap from top to start once the card lays out horizontally. Only start and end can be set at a breakpoint, from sm to xl: @chassis-ui/css has no class for top or bottom there, nor for any value at 2xl: such a value renders no class and warns in development.
ref?any—

CardImageOverlay

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—
PropTypeDefault
active?boolean—
Toggle the active state for the component.
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component. A string of all className you want applied to the base component.
color?ContextColor—
Sets the link color to one of Chassis context colors, including its interactive (:hover/:focus/:active/:visited) states.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
disabled?boolean—
Toggle the disabled state for the component.
href?string—
The href attribute specifies the URL of the page the link goes to. Reaches an <a> or a component reference (a router link); dropped, with a warning in development, when component is another element. Declared explicitly here — rather than left to flow through generically from whatever C is — so consumers that wrap Link (MenuItem, ListItem, NavLink) can read it with a concrete type regardless of component.
iconLink?boolean—
Aligns a leading or trailing icon with the link text using flexbox, with a gap between them and an offset underline. Icons need to be passed as children alongside the text. Named iconLink rather than icon to avoid colliding with components (e.g. MenuItem) that already have their own, differently-typed icon prop for the icon content itself.
onClick?MouseEventHandler<HTMLElement>—
Fires on click.
ref?any—
reset?boolean—
Removes the foreground color override, so the link inherits its color from the nearest ancestor instead of the default link color.
stretched?boolean—
Expands the link's click target to fill its positioned ancestor (the nearest ancestor with a position other than static).
type?"button" | "reset" | "submit"—
Specifies the type of button. Only applies when component="button". Different browsers may use different default types for the <button> element, so always specify it explicitly.

CardSubtitle

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—

CardText

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—

CardTitle

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—