Skip to main content
Light Dark System
Get ready for more awesome! Web Awesome, the next iteration of Shoelace, is on Kickstarter. Read Our Story

Card

<sl-card> | SlCard
Since 2.0 stable

Cards can be used to group related subjects in a container.

A kitten sits patiently between a terracotta pot and decorative grasses. Mittens
This kitten is as cute as he is playful. Bring him home today!
6 weeks old
More Info
<sl-card class="card-overview">
  <img
    slot="image"
    src="https://images.unsplash.com/photo-1559209172-0ff8f6d49ff7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80"
    alt="A kitten sits patiently between a terracotta pot and decorative grasses."
  />

  <strong>Mittens</strong><br />
  This kitten is as cute as he is playful. Bring him home today!<br />
  <small>6 weeks old</small>

  <div slot="footer">
    <sl-button variant="primary" pill>More Info</sl-button>
    <sl-rating></sl-rating>
  </div>
</sl-card>

<style>
  .card-overview {
    max-width: 300px;
  }

  .card-overview small {
    color: var(--sl-color-neutral-500);
  }

  .card-overview [slot='footer'] {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
</style>
import SlButton from '@shoelace-style/shoelace/dist/react/button';
import SlCard from '@shoelace-style/shoelace/dist/react/card';
import SlRating from '@shoelace-style/shoelace/dist/react/rating';

const css = `
  .card-overview {
    max-width: 300px;
  }

  .card-overview small {
    color: var(--sl-color-neutral-500);
  }

  .card-overview [slot="footer"] {
    display: flex; 
    justify-content: space-between; 
    align-items: center;
  }
`;

const App = () => (
  <>
    <SlCard className="card-overview">
      <img
        slot="image"
        src="https://images.unsplash.com/photo-1559209172-0ff8f6d49ff7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80"
        alt="A kitten sits patiently between a terracotta pot and decorative grasses."
      />
      <strong>Mittens</strong>
      <br />
      This kitten is as cute as he is playful. Bring him home today!
      <br />
      <small>6 weeks old</small>
      <div slot="footer">
        <SlButton variant="primary" pill>
          More Info
        </SlButton>
        <SlRating></SlRating>
      </div>
    </SlCard>

    <style>{css}</style>
  </>
);

Examples

Basic Card

Basic cards aren’t very exciting, but they can display any content you want them to.

This is just a basic card. No image, no header, and no footer. Just your content.
<sl-card class="card-basic">
  This is just a basic card. No image, no header, and no footer. Just your content.
</sl-card>

<style>
  .card-basic {
    max-width: 300px;
  }
</style>
import SlCard from '@shoelace-style/shoelace/dist/react/card';

const css = `
  .card-basic {
    max-width: 300px;
  }
`;

const App = () => (
  <>
    <SlCard className="card-basic">
      This is just a basic card. No image, no header, and no footer. Just your content.
    </SlCard>

    <style>{css}</style>
  </>
);

Card with Header

Headers can be used to display titles and more.

Header Title
This card has a header. You can put all sorts of things in it!
<sl-card class="card-header">
  <div slot="header">
    Header Title
    <sl-icon-button name="gear" label="Settings"></sl-icon-button>
  </div>

  This card has a header. You can put all sorts of things in it!
</sl-card>

<style>
  .card-header {
    max-width: 300px;
  }

  .card-header [slot='header'] {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  .card-header h3 {
    margin: 0;
  }

  .card-header sl-icon-button {
    font-size: var(--sl-font-size-medium);
  }
</style>
import SlCard from '@shoelace-style/shoelace/dist/react/card';
import SlIconButton from '@shoelace-style/shoelace/dist/react/icon-button';

const css = `
  .card-header {
    max-width: 300px;
  }

  .card-header [slot="header"] {
    display: flex; 
    align-items: center; 
    justify-content: space-between;
  }

  .card-header h3 {
    margin: 0;
  }

  .card-header sl-icon-button {
    font-size: var(--sl-font-size-medium);
  }
`;

const App = () => (
  <>
    <SlCard className="card-header">
      <div slot="header">
        Header Title
        <SlIconButton name="gear"></SlIconButton>
      </div>
      This card has a header. You can put all sorts of things in it!
    </SlCard>

    <style>{css}</style>
  </>
);

Footers can be used to display actions, summaries, or other relevant content.

This card has a footer. You can put all sorts of things in it!
Preview
<sl-card class="card-footer">
  This card has a footer. You can put all sorts of things in it!

  <div slot="footer">
    <sl-rating></sl-rating>
    <sl-button variant="primary">Preview</sl-button>
  </div>
</sl-card>

<style>
  .card-footer {
    max-width: 300px;
  }

  .card-footer [slot='footer'] {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
</style>
import SlButton from '@shoelace-style/shoelace/dist/react/button';
import SlCard from '@shoelace-style/shoelace/dist/react/card';
import SlRating from '@shoelace-style/shoelace/dist/react/rating';

const css = `
  .card-footer {
    max-width: 300px;
  }

  .card-footer [slot="footer"] {
    display: flex; 
    justify-content: space-between; 
    align-items: center;
  }
`;

const App = () => (
  <>
    <SlCard className="card-footer">
      This card has a footer. You can put all sorts of things in it!
      <div slot="footer">
        <SlRating></SlRating>
        <SlButton slot="footer" variant="primary">
          Preview
        </SlButton>
      </div>
    </SlCard>

    <style>{css}</style>
  </>
);

Images

Cards accept an image slot. The image is displayed atop the card and stretches to fit.

A kitten walks towards camera on top of pallet. This is a kitten, but not just any kitten. This kitten likes walking along pallets.
<sl-card class="card-image">
  <img
    slot="image"
    src="https://images.unsplash.com/photo-1547191783-94d5f8f6d8b1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=80"
    alt="A kitten walks towards camera on top of pallet."
  />
  This is a kitten, but not just any kitten. This kitten likes walking along pallets.
</sl-card>

<style>
  .card-image {
    max-width: 300px;
  }
</style>
import SlCard from '@shoelace-style/shoelace/dist/react/card';

const css = `
  .card-image {
    max-width: 300px;
  }
`;

const App = () => (
  <>
    <SlCard className="card-image">
      <img
        slot="image"
        src="https://images.unsplash.com/photo-1547191783-94d5f8f6d8b1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=80"
        alt="A kitten walks towards camera on top of pallet."
      />
      This is a kitten, but not just any kitten. This kitten likes walking along pallets.
    </SlCard>

    <style>{css}</style>
  </>
);

Horizontal Card

Cards can use horizontal parameter to place the image on the left side.

A kitten walks towards camera on top of pallet. This is a kitten, but not just any kitten. This kitten likes walking along pallets.
<sl-card horizontal>
  <img
    slot="image"
    src="https://images.unsplash.com/photo-1547191783-94d5f8f6d8b1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=80"
    alt="A kitten walks towards camera on top of pallet."
  />
  This is a kitten, but not just any kitten. This kitten likes walking along pallets.
</sl-card>

<style>
</style>

Selectable Card

Cards accept an selectable and selected property. The card then can be selected and used to build complex ‘visual checkboxes’. The selectable enables the selection/checked logic and selected is the reflective state property.

A kitten walks towards camera on top of pallet. (de-)select me‼!

isCardSelected:

A kitten walks towards camera on top of pallet. (de-)select me‼! with custom selection style
<div style="display:flex; gap:20px">
  <div style="display:flex;flex-direction:column">
    <sl-card id="cardItem" class="card-image" selectable selected>
      <img
        slot="image"
        src="https://images.unsplash.com/photo-1547191783-94d5f8f6d8b1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=80"
        alt="A kitten walks towards camera on top of pallet."
      />
      (de-)select me!!!
    </sl-card>

    <p>isCardSelected: <span id="card-status"></span></p>
  </div>
  
  
  <sl-card id="cardItem2" class="card-image" selectable selected>
    <img
      slot="image"
      src="https://images.unsplash.com/photo-1547191783-94d5f8f6d8b1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=80"
      alt="A kitten walks towards camera on top of pallet."
    />
    (de-)select me!!! with custom selection style
  </sl-card>
</div>

<style>
#cardItem2[selected]::part(base){
  border:5px solid red;
}
</style>

<script>
document.querySelector('#card-status').innerHTML = cardItem.selected
document.querySelector('#cardItem').addEventListener('sl-change',(ev)=>{
      let cardItem = ev.target.closest('sl-card')
      console.log('cardItem state changed', ev, cardItem, cardItem.selected)
      document.querySelector('#card-status').innerHTML = cardItem.selected
      ev.stopPropagation();
    })
</script>

<style>
  .card-image {
    max-width: 300px;
  }
</style>

Importing

If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.

Script Import Bundler React

To import this component from the CDN using a script tag:

<script type="module" src="https://cdn.jsdelivr.net/npm/@viur/shoelace@1.0.8-v2.19.1/cdn/components/card/card.js"></script>

To import this component from the CDN using a JavaScript import:

import 'https://cdn.jsdelivr.net/npm/@viur/shoelace@1.0.8-v2.19.1/cdn/components/card/card.js';

To import this component using a bundler:

import '@viur/shoelace/dist/components/card/card.js';

To import this component as a React component:

import SlCard from '@viur/shoelace/dist/react/card';

Slots

Name Description
(default) The card’s main content.
header An optional header for the card.
footer An optional footer for the card.
image An optional image to render at the start of the card.

Learn more about using slots.

Properties

Name Description Reflects Type Default
selectable Allows selecting the card via click or programmatically. boolean false
selected Draws the checkbox in a selected state. boolean false
horizontal vertical card boolean false
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Events

Name React Event Description Event Detail
sl-change onSlChange Emitted when the control’s checked state changes. -

Learn more about events.

Custom Properties

Name Description Default
--border-color The card’s border color, including borders that occur inside the card.
--border-radius The border radius for the card’s edges.
--border-width The width of the card’s borders.
--padding The padding to use for the card’s sections.

Learn more about customizing CSS custom properties.

Parts

Name Description
base The component’s base wrapper.
image The container that wraps the card’s image.
header The container that wraps the card’s header.
body The container that wraps the card’s main content.
footer The container that wraps the card’s footer.

Learn more about customizing CSS parts.