Skip to main content

Theme config

Theme mode

Color palette

Grays

Border radii/radiuses/radiopedes/you know
Border radius
Field border radius
Button border radius
All
Components
Guides
API
Recent

    Components

    Card

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

    Full supportSupported since v111.Full supportSupported since v151.Full supportSupported since v18.

    Anatomy

    Overline

    Headline

    Subhead

    Explain more about the topic shown in the headline and subhead through supporting text.
    • <Card>

      Container element.

    • v-slot:header

      The card header.

    • v-slot:content

      The card content.

    • v-slot:actions

      A group of actions, such as buttons.

    Variants

    Change the card variant with the variant prop.

    Text
    Outlined
    Tonal
    Elevated
    <script setup lang="ts">
    import { Card } from "opui-css/vue"
    </script>
    <template>
    <Card variant="text">
    <template #content>Text</template>
    </Card>
    <Card variant="outlined">
    <template #content>Outlined</template>
    </Card>
    <Card variant="tonal">
    <template #content>Tonal</template>
    </Card>
    <Card variant="elevated">
    <template #content>Elevated</template>
    </Card>
    </template>
    <!--[-->
    <div class="ui-card ui-text">
    <!---->
    <div class="ui-content"><!--[-->Text<!--]--></div>
    <!--[--><!--]--><!---->
    </div>
    <div class="ui-card ui-outlined">
    <!---->
    <div class="ui-content"><!--[-->Outlined<!--]--></div>
    <!--[--><!--]--><!---->
    </div>
    <div class="ui-card ui-tonal">
    <!---->
    <div class="ui-content"><!--[-->Tonal<!--]--></div>
    <!--[--><!--]--><!---->
    </div>
    <div class="ui-card ui-elevated">
    <!---->
    <div class="ui-content"><!--[-->Elevated<!--]--></div>
    <!--[--><!--]--><!---->
    </div>
    <!--]-->

    Why does a text variant exist?

    It really doesn't make sense to use the text variant unless you really need to. The accordion group is a great example where Open Props UI leverages the text variant of the.ui-card component.

    Using the header slot.

    Blog

    My ultra-great blog post

    Please read it.

    <script setup lang="ts">
    import { Card } from "opui-css/vue"
    </script>
    <template>
    <Card variant="outlined">
    <template #header>
    <p>Blog</p>
    <h3>My ultra-great blog post</h3>
    <p>Please read it.</p>
    </template>
    </Card>
    </template>
    <div class="ui-card ui-outlined">
    <hgroup>
    <!--[-->
    <p>Blog</p>
    <h3>My ultra-great blog post</h3>
    <p>Please read it.</p>
    <!--]-->
    </hgroup>
    <!----><!--[--><!--]--><!---->
    </div>

    Actions

    Using the actions slot.

    There are some basic styles here to get you going, but for more advanced use-cases (which always happen), you might want to add your own styles.

    Notice how the buttons are made to align with the text above.
    Trying other button types too. Look at that!
    Icon buttons work too!
    <script setup lang="ts">
    import { Button, Card, IconButton } from "opui-css/vue"
    </script>
    <template>
    <Card variant="outlined">
    <template #content>
    Notice how the buttons are made to align with the text above.
    </template>
    <template #actions>
    <Button>Cancel</Button>
    <Button>Save</Button>
    </template>
    </Card>
    <Card variant="outlined">
    <template #content>Trying other button types too. Look at that!</template>
    <template #actions>
    <Button variant="outlined">Cancel</Button>
    <Button variant="filled">Save</Button>
    </template>
    </Card>
    <Card variant="outlined">
    <template #content>Icon buttons work too!</template>
    <template #actions>
    <IconButton aria-label="Favorite">
    <svg
    xmlns="http://www.w3.org/2000/svg"
    width="32"
    height="32"
    viewBox="0 0 32 32"
    >
    <path
    fill="currentColor"
    d="M3.384 7.13c2.972-4.17 9.167-4.174 12.146-.008l.465.65l.417-.593c2.955-4.195 9.16-4.236 12.17-.081A7.48 7.48 0 0 1 28 16.583L16.732 28.681a1 1 0 0 1-1.464 0L3.992 16.54a7.46 7.46 0 0 1-.608-9.41m10.52 1.155c-2.181-3.05-6.716-3.046-8.892.007a5.46 5.46 0 0 0 .446 6.887L16.002 26.53l10.534-11.31a5.48 5.48 0 0 0 .427-6.95c-2.205-3.044-6.751-3.013-8.916.06l-1.229 1.744a1 1 0 0 1-1.63.006z"
    ></path>
    </svg>
    </IconButton>
    <IconButton aria-label="Share">
    <svg
    xmlns="http://www.w3.org/2000/svg"
    width="32"
    height="32"
    viewBox="0 0 32 32"
    >
    <path
    fill="currentColor"
    d="M14 3a1 1 0 1 1 0 2H7.5A2.5 2.5 0 0 0 5 7.5v17A2.5 2.5 0 0 0 7.5 27h17a2.5 2.5 0 0 0 2.5-2.5V19a1 1 0 1 1 2 0v5.5a4.5 4.5 0 0 1-4.5 4.5h-17A4.5 4.5 0 0 1 3 24.5v-17A4.5 4.5 0 0 1 7.5 3zm5.58-.907a1 1 0 0 1 1.067.146l10 8.5a1 1 0 0 1 0 1.523l-10 8.5A1 1 0 0 1 18.999 20v-3.96c-3.193.258-5.636 1.722-7.34 3.213a15.6 15.6 0 0 0-2.115 2.26c-.234.307-.407.56-.52.733c-.085.13-.136.215-.152.243l-.006.006l.001.001A1 1 0 0 1 7 22.036c0-.222-.003-.444.003-.666c.011-.406.042-.982.12-1.67c.155-1.37.5-3.218 1.265-5.08s1.967-3.776 3.855-5.225C13.948 8.086 16.161 7.2 19 7.032V3a1 1 0 0 1 .58-.907M20.998 8a1 1 0 0 1-1 1c-2.925 0-5.018.814-6.539 1.98c-1.533 1.177-2.551 2.763-3.224 4.4a16.5 16.5 0 0 0-.957 3.38c.318-.33.672-.672 1.062-1.013C12.462 15.891 15.687 14 19.999 14a1 1 0 0 1 1 1v2.838l7.456-6.338L21 5.161z"
    ></path>
    </svg>
    </IconButton>
    </template>
    </Card>
    </template>
    <!--[-->
    <div class="ui-card ui-outlined">
    <!---->
    <div class="ui-content">
    <!--[-->
    Notice how the buttons are made to align with the text above.
    <!--]-->
    </div>
    <!--[--><!--]-->
    <div class="ui-actions">
    <!--[--><button class="ui-button"><!--[-->Cancel<!--]--></button
    ><button class="ui-button"><!--[-->Save<!--]--></button><!--]-->
    </div>
    </div>
    <div class="ui-card ui-outlined">
    <!---->
    <div class="ui-content">
    <!--[-->Trying other button types too. Look at that!<!--]-->
    </div>
    <!--[--><!--]-->
    <div class="ui-actions">
    <!--[--><button class="ui-button ui-outlined"><!--[-->Cancel<!--]--></button
    ><button class="ui-button ui-filled"><!--[-->Save<!--]--></button><!--]-->
    </div>
    </div>
    <div class="ui-card ui-outlined">
    <!---->
    <div class="ui-content"><!--[-->Icon buttons work too!<!--]--></div>
    <!--[--><!--]-->
    <div class="ui-actions">
    <!--[--><button class="ui-icon-button" aria-label="Favorite">
    <!--[--><svg
    xmlns="http://www.w3.org/2000/svg"
    width="32"
    height="32"
    viewBox="0 0 32 32"
    >
    <path
    fill="currentColor"
    d="M3.384 7.13c2.972-4.17 9.167-4.174 12.146-.008l.465.65l.417-.593c2.955-4.195 9.16-4.236 12.17-.081A7.48 7.48 0 0 1 28 16.583L16.732 28.681a1 1 0 0 1-1.464 0L3.992 16.54a7.46 7.46 0 0 1-.608-9.41m10.52 1.155c-2.181-3.05-6.716-3.046-8.892.007a5.46 5.46 0 0 0 .446 6.887L16.002 26.53l10.534-11.31a5.48 5.48 0 0 0 .427-6.95c-2.205-3.044-6.751-3.013-8.916.06l-1.229 1.744a1 1 0 0 1-1.63.006z"
    ></path></svg
    ><!--]--></button
    ><button class="ui-icon-button" aria-label="Share">
    <!--[--><svg
    xmlns="http://www.w3.org/2000/svg"
    width="32"
    height="32"
    viewBox="0 0 32 32"
    >
    <path
    fill="currentColor"
    d="M14 3a1 1 0 1 1 0 2H7.5A2.5 2.5 0 0 0 5 7.5v17A2.5 2.5 0 0 0 7.5 27h17a2.5 2.5 0 0 0 2.5-2.5V19a1 1 0 1 1 2 0v5.5a4.5 4.5 0 0 1-4.5 4.5h-17A4.5 4.5 0 0 1 3 24.5v-17A4.5 4.5 0 0 1 7.5 3zm5.58-.907a1 1 0 0 1 1.067.146l10 8.5a1 1 0 0 1 0 1.523l-10 8.5A1 1 0 0 1 18.999 20v-3.96c-3.193.258-5.636 1.722-7.34 3.213a15.6 15.6 0 0 0-2.115 2.26c-.234.307-.407.56-.52.733c-.085.13-.136.215-.152.243l-.006.006l.001.001A1 1 0 0 1 7 22.036c0-.222-.003-.444.003-.666c.011-.406.042-.982.12-1.67c.155-1.37.5-3.218 1.265-5.08s1.967-3.776 3.855-5.225C13.948 8.086 16.161 7.2 19 7.032V3a1 1 0 0 1 .58-.907M20.998 8a1 1 0 0 1-1 1c-2.925 0-5.018.814-6.539 1.98c-1.533 1.177-2.551 2.763-3.224 4.4a16.5 16.5 0 0 0-.957 3.38c.318-.33.672-.672 1.062-1.013C12.462 15.891 15.687 14 19.999 14a1 1 0 0 1 1 1v2.838l7.456-6.338L21 5.161z"
    ></path></svg
    ><!--]--></button
    ><!--]-->
    </div>
    </div>
    <!--]-->

    Alignment

    Align actions to the end with the actionsAlign="end" prop.

    Buttons aligned to the end. Works too!
    Again, buttons are aligned to the end!
    Icon buttons aligned to the end!
    <script setup lang="ts">
    import { Button, Card, IconButton } from "opui-css/vue"
    </script>
    <template>
    <Card variant="outlined" actionsAlign="end">
    <template #content>Buttons aligned to the end. Works too!</template>
    <template #actions>
    <Button>Cancel</Button>
    <Button>Save</Button>
    </template>
    </Card>
    <Card variant="outlined" actionsAlign="end">
    <template #content>Again, buttons are aligned to the end!</template>
    <template #actions>
    <Button variant="outlined">Cancel</Button>
    <Button variant="filled">Save</Button>
    </template>
    </Card>
    <Card variant="outlined" actionsAlign="end">
    <template #content>Icon buttons aligned to the end!</template>
    <template #actions>
    <IconButton aria-label="Favorite">
    <svg
    xmlns="http://www.w3.org/2000/svg"
    width="32"
    height="32"
    viewBox="0 0 32 32"
    >
    <path
    fill="currentColor"
    d="M3.384 7.13c2.972-4.17 9.167-4.174 12.146-.008l.465.65l.417-.593c2.955-4.195 9.16-4.236 12.17-.081A7.48 7.48 0 0 1 28 16.583L16.732 28.681a1 1 0 0 1-1.464 0L3.992 16.54a7.46 7.46 0 0 1-.608-9.41m10.52 1.155c-2.181-3.05-6.716-3.046-8.892.007a5.46 5.46 0 0 0 .446 6.887L16.002 26.53l10.534-11.31a5.48 5.48 0 0 0 .427-6.95c-2.205-3.044-6.751-3.013-8.916.06l-1.229 1.744a1 1 0 0 1-1.63.006z"
    ></path>
    </svg>
    </IconButton>
    <IconButton aria-label="Share">
    <svg
    xmlns="http://www.w3.org/2000/svg"
    width="32"
    height="32"
    viewBox="0 0 32 32"
    >
    <path
    fill="currentColor"
    d="M14 3a1 1 0 1 1 0 2H7.5A2.5 2.5 0 0 0 5 7.5v17A2.5 2.5 0 0 0 7.5 27h17a2.5 2.5 0 0 0 2.5-2.5V19a1 1 0 1 1 2 0v5.5a4.5 4.5 0 0 1-4.5 4.5h-17A4.5 4.5 0 0 1 3 24.5v-17A4.5 4.5 0 0 1 7.5 3zm5.58-.907a1 1 0 0 1 1.067.146l10 8.5a1 1 0 0 1 0 1.523l-10 8.5A1 1 0 0 1 18.999 20v-3.96c-3.193.258-5.636 1.722-7.34 3.213a15.6 15.6 0 0 0-2.115 2.26c-.234.307-.407.56-.52.733c-.085.13-.136.215-.152.243l-.006.006l.001.001A1 1 0 0 1 7 22.036c0-.222-.003-.444.003-.666c.011-.406.042-.982.12-1.67c.155-1.37.5-3.218 1.265-5.08s1.967-3.776 3.855-5.225C13.948 8.086 16.161 7.2 19 7.032V3a1 1 0 0 1 .58-.907M20.998 8a1 1 0 0 1-1 1c-2.925 0-5.018.814-6.539 1.98c-1.533 1.177-2.551 2.763-3.224 4.4a16.5 16.5 0 0 0-.957 3.38c.318-.33.672-.672 1.062-1.013C12.462 15.891 15.687 14 19.999 14a1 1 0 0 1 1 1v2.838l7.456-6.338L21 5.161z"
    ></path>
    </svg>
    </IconButton>
    </template>
    </Card>
    </template>
    <!--[-->
    <div class="ui-card ui-outlined">
    <!---->
    <div class="ui-content">
    <!--[-->Buttons aligned to the end. Works too!<!--]-->
    </div>
    <!--[--><!--]-->
    <div class="ui-actions ui-align-end">
    <!--[--><button class="ui-button"><!--[-->Cancel<!--]--></button
    ><button class="ui-button"><!--[-->Save<!--]--></button><!--]-->
    </div>
    </div>
    <div class="ui-card ui-outlined">
    <!---->
    <div class="ui-content">
    <!--[-->Again, buttons are aligned to the end!<!--]-->
    </div>
    <!--[--><!--]-->
    <div class="ui-actions ui-align-end">
    <!--[--><button class="ui-button ui-outlined"><!--[-->Cancel<!--]--></button
    ><button class="ui-button ui-filled"><!--[-->Save<!--]--></button><!--]-->
    </div>
    </div>
    <div class="ui-card ui-outlined">
    <!---->
    <div class="ui-content"><!--[-->Icon buttons aligned to the end!<!--]--></div>
    <!--[--><!--]-->
    <div class="ui-actions ui-align-end">
    <!--[--><button class="ui-icon-button" aria-label="Favorite">
    <!--[--><svg
    xmlns="http://www.w3.org/2000/svg"
    width="32"
    height="32"
    viewBox="0 0 32 32"
    >
    <path
    fill="currentColor"
    d="M3.384 7.13c2.972-4.17 9.167-4.174 12.146-.008l.465.65l.417-.593c2.955-4.195 9.16-4.236 12.17-.081A7.48 7.48 0 0 1 28 16.583L16.732 28.681a1 1 0 0 1-1.464 0L3.992 16.54a7.46 7.46 0 0 1-.608-9.41m10.52 1.155c-2.181-3.05-6.716-3.046-8.892.007a5.46 5.46 0 0 0 .446 6.887L16.002 26.53l10.534-11.31a5.48 5.48 0 0 0 .427-6.95c-2.205-3.044-6.751-3.013-8.916.06l-1.229 1.744a1 1 0 0 1-1.63.006z"
    ></path></svg
    ><!--]--></button
    ><button class="ui-icon-button" aria-label="Share">
    <!--[--><svg
    xmlns="http://www.w3.org/2000/svg"
    width="32"
    height="32"
    viewBox="0 0 32 32"
    >
    <path
    fill="currentColor"
    d="M14 3a1 1 0 1 1 0 2H7.5A2.5 2.5 0 0 0 5 7.5v17A2.5 2.5 0 0 0 7.5 27h17a2.5 2.5 0 0 0 2.5-2.5V19a1 1 0 1 1 2 0v5.5a4.5 4.5 0 0 1-4.5 4.5h-17A4.5 4.5 0 0 1 3 24.5v-17A4.5 4.5 0 0 1 7.5 3zm5.58-.907a1 1 0 0 1 1.067.146l10 8.5a1 1 0 0 1 0 1.523l-10 8.5A1 1 0 0 1 18.999 20v-3.96c-3.193.258-5.636 1.722-7.34 3.213a15.6 15.6 0 0 0-2.115 2.26c-.234.307-.407.56-.52.733c-.085.13-.136.215-.152.243l-.006.006l.001.001A1 1 0 0 1 7 22.036c0-.222-.003-.444.003-.666c.011-.406.042-.982.12-1.67c.155-1.37.5-3.218 1.265-5.08s1.967-3.776 3.855-5.225C13.948 8.086 16.161 7.2 19 7.032V3a1 1 0 0 1 .58-.907M20.998 8a1 1 0 0 1-1 1c-2.925 0-5.018.814-6.539 1.98c-1.533 1.177-2.551 2.763-3.224 4.4a16.5 16.5 0 0 0-.957 3.38c.318-.33.672-.672 1.062-1.013C12.462 15.891 15.687 14 19.999 14a1 1 0 0 1 1 1v2.838l7.456-6.338L21 5.161z"
    ></path></svg
    ><!--]--></button
    ><!--]-->
    </div>
    </div>
    <!--]-->

    API

    Card API

    PropTypeDefaultDescription
    actionsAlign"start", "end"-Alignment for the actions.
    variant"outlined", "elevated", "tonal", "text"-The variant to use.

    Slots

    SlotDescription
    actionsA group of actions, such as buttons.
    contentThe card content.
    defaultRaw content placed directly in the card.
    headerThe card header.

    Browser support

    Full supportSupported since v111.Full supportSupported since v151.Full supportSupported since v18.

    See also the full browser support guide.

    Installation

    Other components might depend on the card component. Be mindful when making changes. Accordion, Dialog
    @layer components.root {
    :where(.ui-card) {
    --_bg-tonal: var(--surface-tonal);
    --_bg-elevated: var(--surface-elevated);
    --_bg-surface: var(--surface-default);
    --_border-color: var(--border-color);
    --_card-bg-color: var(--_bg-surface);
    --_card-border-color: transparent;
    --_card-border-width: 0;
    --_card-shadow: none;
    --_shadow-light: var(--shadow-3);
    --_shadow-dark: var(--shadow-4);
    --_shadow-elevated: var(--_shadow-light);
    @container style(--color-scheme: dark) {
    --_shadow-elevated: var(--_shadow-dark);
    }
    background-color: var(--_card-bg-color);
    border-color: var(--_card-border-color);
    border-radius: var(--border-radius);
    border-style: solid;
    border-width: var(--_card-border-width);
    box-shadow: var(--_card-shadow);
    display: flex;
    flex-direction: column;
    gap: var(--size-3);
    overflow: hidden;
    padding-inline: 0;
    position: relative;
    /* Variants */
    &.ui-text {
    --_card-bg-color: transparent;
    --_card-border-color: transparent;
    --_card-border-width: 0;
    --_card-shadow: none;
    }
    &.ui-tonal {
    --_card-bg-color: var(--_bg-tonal);
    --_card-border-width: 1px;
    }
    &.ui-elevated {
    --_card-bg-color: var(--_bg-elevated);
    --_card-shadow: var(--_shadow-elevated);
    }
    &.ui-outlined {
    --_card-bg-color: var(--_bg-surface);
    --_card-border-color: var(--_border-color);
    --_card-border-width: 1px;
    }
    & > :where(hgroup, .ui-content) {
    padding-inline: var(--size-3);
    &:last-child {
    padding-block-end: var(--size-3);
    }
    }
    /* Header */
    & > hgroup {
    padding-block: var(--size-3) 0;
    /* Top paragraph */
    & > p:first-of-type:first-child {
    font-size: var(--font-size-0);
    line-height: 1.3;
    }
    :where(h1, h2, h3, h4, h5, h6):last-child {
    margin-block-end: 0;
    }
    /* Bottom paragraph */
    & > p:last-of-type:last-child:not(:first-child) {
    font-size: var(--font-size-1);
    }
    }
    /* Content */
    & > .ui-content:where(:only-child, :first-child) {
    padding-block: var(--size-3) var(--size-4);
    }
    /* Actions */
    & > .ui-actions {
    display: flex;
    gap: var(--size-2);
    margin-block: var(--size-2) 0;
    padding-block-end: var(--size-2);
    padding-inline: var(--size-3);
    &:has(.ui-button:first-child[class="ui-button"]) {
    padding-inline: var(--size-1) var(--size-3);
    }
    &:has(.ui-button:not([class="ui-button"])) {
    padding-block-end: var(--size-2);
    }
    /* Alignment */
    &.ui-align-end {
    justify-content: end;
    &:has(.ui-button:first-child[class="ui-button"]) {
    padding-inline: var(--size-3) var(--size-1);
    }
    }
    }
    }
    }