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 support Supported since v111. Unsupported
Does not support:
container-style-queries.
Full support Supported since v18. Variants
Change the card variant with the .text, .outlined, .tonal, and .elevated classes.
Text
Outlined
Tonal
Elevated
<!-- .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>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.card component.
Header
Using the <hgroup>.
Blog
My ultra-great blog post
Please read it.
<div class="card outlined"> <hgroup> <p>Blog</p> <h3>My ultra-great blog post</h3> <p>Please read it.</p> </hgroup></div>Actions
Using the .actions class.
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!
<div class="card outlined"> <div class="content"> Notice how the buttons are made to align with the text above. </div> <div class="actions"> <button class="button">Cancel</button> <button class="button">Save</button> </div></div>
<div class="card outlined"> <div class="content"> Trying other button types too. Look at that! </div> <div class="actions"> <button class="button outlined">Cancel</button> <button class="button filled">Save</button> </div></div>
<div class="card outlined"> <div class="content"> Icon buttons work too! </div> <div class="actions"> <button class="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" /> </svg> </button> <button class="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" /> </svg> </button>
</div></div>Alignment
Align actions to the end with the .align-end class.
Buttons aligned to the end. Works too!
Again, buttons are aligned to the end!
Icon buttons aligned to the end!
<div class="card outlined"> <div class="content"> Buttons aligned to the end. Works too! </div> <div class="actions align-end"> <button class="button">Cancel</button> <button class="button">Save</button> </div></div>
<div class="card outlined"> <div class="content"> Again, buttons are aligned to the end! </div> <div class="actions align-end"> <button class="button outlined">Cancel</button> <button class="button filled">Save</button> </div></div>
<div class="card outlined"> <div class="content"> Icon buttons aligned to the end! </div> <div class="actions align-end"> <button class="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" /> </svg> </button> <button class="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" /> </svg> </button> </div></div>Anatomy
Open Props UI include these complementary utility components to handle various use cases:
- Container
<hgroup>(optional): a wrapper for the card header.content(optional): a wrapper for the card content.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.
<div class="card elevated anatomy"> <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
| Type | Modifiers | Default | Description |
|---|---|---|---|
| Children | & > hgroup, & > .content, & > .actions | - | Optional wrappers for child content. |
| Variants | .text, .outlined, .tonal, .elevated | .text | The variant to use. |
| Alignment | .actions.align-end | - | Align actions to the end. |
Browser support
Full support Supported since v111. Unsupported
Does not support:
container-style-queries.
Full support Supported since v18. See also the full browser support guide.
Installation
@layer components.root { :where(.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 */ &.text { --_card-bg-color: transparent; --_card-border-color: transparent; --_card-border-width: 0; --_card-shadow: none; }
&.tonal { --_card-bg-color: var(--_bg-tonal); --_card-border-width: 1px; }
&.elevated { --_card-bg-color: var(--_bg-elevated); --_card-shadow: var(--_shadow-elevated); }
&.outlined { --_card-bg-color: var(--_bg-surface); --_card-border-color: var(--_border-color); --_card-border-width: 1px; }
&> :where(hgroup, .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 { 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 */ &>.content:where(:only-child, :first-child) { padding-block: var(--size-3) var(--size-4); }
/* Actions */ &>.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(.button:first-child[class="button"]) { padding-inline: var(--size-1) var(--size-3); }
&:has(.button:not([class="button"])) { padding-block-end: var(--size-2); }
/* Alignment */ &.align-end { justify-content: end;
&:has(.button:first-child[class="button"]) { padding-inline: var(--size-3) var(--size-1); } } }
}}