Skip to content

Components

Card

The card is extremely versetile and can be used on its own, or as a building block for accordions, dialogs and more.

Variants

Text
Outlined
Tonal
Elevated
html
<!-- .text class optional -->
<div class="card text">
  <div class="content">Text</div>
</div>

<div class="card outlined">
  <div class="content">Outlined</div>
</div>

<div class="card tonal">
  <div class="content">Tonal</div>
</div>

<div class="card elevated">
  <div class="content">Elevated</div>
</div>

Anatomy

Open Props UI include these complementary utility components to handle various use cases:

  1. Container
  2. <hgroup> (optional): a wrapper for the card header
  3. .content (optional): a wrapper for the card content
  4. .actions (optional): a wrapper that groups a set of buttons

Overline

Headline

Subhead

Explain more about the topic shown in the headline and subhead through supporting text.
html
<div class="card outlined">
  <hgroup>
    <p>Overline</p>
    <h2 class="h3">Headline</h2>
    <p>Subhead</p>
  </hgroup>
  <div class="content">
    Explain more about the topic shown in the headline and subhead through
    supporting text.
  </div>
  <div class="actions">
    <button class="button">Share</button>
    <button class="button">Learn more</button>
  </div>
</div>

API

These are the classes and attributes a card can be styled with. As usual, feel free to add your own!

TypeModifiersDefaultDescription
Children& > <hgroup>, & > .content, & > .actions-Optional wrappers for child content.
Variants.text, .outlined, .tonal, .elevated.textThe variant to use.

See also

Browser compatibility

Installation

css
@layer components.base {
  :where(.card) {
    --_bg-color: transparent;
    --_border-color: transparent;
    --_border-width: 0;
    --_shadow: none;

    background-color: var(--_bg-color);
    border-color: var(--_border-color);
    border-radius: var(--border-radius, 0.25rem);
    border-style: solid;
    border-width: var(--_border-width);
    box-shadow: var(--_shadow);
    display: flex;
    flex-direction: column;
    gap: var(--size-3);
    overflow: hidden;
    padding-inline: 0;

    /* Variants */
    &.text {
      --_bg-color: transparent;
      --_border-color: transparent;
      --_border-width: 0;
      --_shadow: none;
      padding-inline: 0;
    }

    &.tonal {
      --_bg-color: var(--surface-tonal);
      --_border-width: 1px;
    }

    &.elevated {
      --_bg-color: var(--surface-elevated);
      --_border-color: transparent;
      --_border-width: 0;
      --_shadow: var(--shadow-3);

      /* Adjust shadow in dark mode */
      @container style(--color-scheme: dark) {
        --_shadow: var(--shadow-4);
      }
    }

    &.outlined {
      --_bg-color: var(--surface-default);
      --_border-color: var(--border-color);
      --_border-width: 1px;
    }

    & > :where(hgroup, .content) {
      padding-inline: var(--size-3);
    }

    & > hgroup {
      padding-block: var(--size-3) 0;

      /* Top paragraph */
      & > p:first-of-type:first-child {
        line-height: 1.3;
      }

      /* Bottom paragraph */
      & > p:last-of-type:last-child:not(:first-child) {
        font-size: var(--font-size-1, 1rem);
      }
    }

    & > .content:where(:only-child, :first-child) {
      padding-block: var(--size-3) var(--size-4);
    }

    & > .actions {
      display: flex;
      gap: var(--size-1);
      margin-block: var(--size-2) 0;
      padding-block-end: var(--size-1);
      padding-inline: var(--size-1) var(--size-3);
    }
  }
}