Cards

Bootstrap · Lesson 10 of 28 6 min read Updated

A card is a bordered box that groups related content: a product with its photo and price, a course with its duration, a team member with a short bio. Cards are probably the most used Bootstrap component, because they look good alone and even better in a grid.

In this lesson you will build cards from their parts, arrange them in responsive grids with equal heights, and make horizontal and fully clickable cards.

The parts of a card

A card is a div with the card class. Inside it, you combine the parts you need:

ClassRole
card-bodyThe padded main area. Most content goes here
card-title, card-subtitleHeading and smaller sub-heading
card-textA paragraph (removes the bottom margin of the last one)
card-img-top, card-img-bottomAn image flush with the top or bottom edge, with matching rounded corners
card-header, card-footerShaded strips above and below the body
card-linkLinks placed side by side
HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Card parts</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container py-3">
    <div class="row g-3">
      <div class="col-md-6">
        <div class="card">
          <img src="https://course.ethicscomputer.in/assets/samples/landscape-400.svg" class="card-img-top" alt="Hills near Munnar" width="400" height="250">
          <div class="card-body">
            <h2 class="card-title h5">Munnar Weekend Trip</h2>
            <h3 class="card-subtitle h6 mb-2 text-body-secondary">2 nights, from Kochi</h3>
            <p class="card-text">Tea gardens, Eravikulam National Park and a sunrise at Top Station. Hotel and transport included.</p>
            <a href="#book" class="btn btn-primary">Book for ₹6,499</a>
          </div>
        </div>
      </div>
      <div class="col-md-6">
        <div class="card">
          <div class="card-header">Today's batch</div>
          <div class="card-body">
            <h2 class="card-title h5">Python for Beginners</h2>
            <p class="card-text">Rohtak centre, 6 pm to 8 pm. Twelve seats left.</p>
            <a href="#syllabus" class="card-link">Syllabus</a>
            <a href="#trainer" class="card-link">Trainer</a>
          </div>
          <ul class="list-group list-group-flush">
            <li class="list-group-item">Duration: 8 weeks</li>
            <li class="list-group-item">Mode: Classroom</li>
          </ul>
          <div class="card-footer text-body-secondary">Starts Monday</div>
        </div>
      </div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

The second card contains a list group: list-group on a <ul> and list-group-item on each <li>. Adding list-group-flush removes its outer borders and rounded corners so it sits neatly inside the card. List groups are also useful on their own, for menus and settings lists; add list-group-item-action to items that are links or buttons to get a hover effect.

Cards have no fixed width. They fill their parent, so control their size with grid columns or sizing classes, never with a width on the card itself.

Card grids with equal heights

Put each card in a grid column and use row-cols-* to set how many per row. One problem appears at once: cards with less text are shorter than their neighbours. Add h-100 to every card so it fills the full height of its column, and the row looks tidy.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Card grid</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container py-3">
    <h1 class="h4 mb-3">Kirana Fresh: today's offers</h1>
    <div class="row row-cols-1 row-cols-sm-2 row-cols-lg-3 g-3">
      <div class="col">
        <div class="card h-100">
          <div class="card-body">
            <h2 class="card-title h6">Basmati rice, 5 kg</h2>
            <p class="card-text">Aged long-grain rice.</p>
          </div>
          <div class="card-footer d-flex justify-content-between align-items-center">
            <span class="fw-bold">₹549</span>
            <button type="button" class="btn btn-sm btn-success">Add</button>
          </div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100">
          <div class="card-body">
            <h2 class="card-title h6">Toor dal, 1 kg</h2>
            <p class="card-text">Unpolished, from Maharashtra farms. Cooks soft in 3 whistles and keeps its flavour.</p>
          </div>
          <div class="card-footer d-flex justify-content-between align-items-center">
            <span class="fw-bold">₹168</span>
            <button type="button" class="btn btn-sm btn-success">Add</button>
          </div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100 border-warning">
          <div class="card-body">
            <span class="badge text-bg-warning mb-2">Only 4 left</span>
            <h2 class="card-title h6">Cold-pressed groundnut oil, 1 L</h2>
            <p class="card-text">Wood-pressed, no chemicals.</p>
          </div>
          <div class="card-footer d-flex justify-content-between align-items-center">
            <span class="fw-bold">₹289</span>
            <button type="button" class="btn btn-sm btn-success">Add</button>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Because each card is a flex column, the card-footer always sits at the bottom, so the prices and buttons line up across the row even when the descriptions have different lengths. Colour a card with border-* (as the oil card does), with text-bg-* for a solid background, or with bg-*-subtle for a soft tint.

If you want cards glued together with shared borders and no gaps, wrap them in a card-group instead of a grid row. It is less flexible, but good for a three-plan pricing strip.

Horizontal cards

For a list of results, an image on the left and text on the right reads better. Use a grid inside the card, with g-0 to remove the gutters:

HTML
<div class="card mb-3">
  <div class="row g-0">
    <div class="col-md-4">
      <img src="https://course.ethicscomputer.in/assets/samples/portrait.svg" class="img-fluid rounded-start" alt="Book cover">
    </div>
    <div class="col-md-8">
      <div class="card-body">
        <h2 class="card-title h5">Wings of Fire</h2>
        <p class="card-text">Autobiography of Dr A. P. J. Abdul Kalam. Paperback, ₹299.</p>
        <p class="card-text"><small class="text-body-secondary">Ships from Lucknow in 2 days</small></p>
      </div>
    </div>
  </div>
</div>

On phones the image stacks above the text; from md they sit side by side. rounded-start rounds only the image's left corners to match the card.

Making the whole card clickable

Users often try to click anywhere on a product card. Add stretched-link to the main link inside the card: an invisible layer stretches the link over the whole card, which already has position: relative.

HTML
<div class="card">
  <div class="card-body">
    <h2 class="card-title h5">Rajasthani thali</h2>
    <p class="card-text">Dal baati churma, gatte, ker sangri. ₹320.</p>
    <a href="/menu/thali" class="stretched-link">View dish</a>
  </div>
</div>

Use only one stretched link per card. Other buttons inside the card will be covered by it unless you give them position-relative.

Image overlays

card-img-overlay places the body on top of the image, like a poster. Make sure the text is readable over the image: use dark images with text-white, or a dark semi-transparent background on the text.

HTML
<div class="card text-white">
  <img src="https://course.ethicscomputer.in/assets/samples/landscape.svg" class="card-img" alt="Sunset over the hills">
  <div class="card-img-overlay d-flex align-items-end">
    <h2 class="card-title h4 bg-dark bg-opacity-50 p-2 rounded">Diwali sale: up to 40% off</h2>
  </div>
</div>

Common mistakes

  • Setting a width on the card. The layout breaks on phones. Let the grid column control the width.
  • Uneven card heights in a grid. Add h-100 to each card, and put actions in a card-footer so they line up.
  • Several stretched-links in one card. Only the last one works across the card; others are hidden under it.
  • Images without card-img-top. A plain image keeps square corners that stick out of the rounded card.

Key points

  • A card is card plus parts such as card-body, card-title, card-text, card-img-top, card-header and card-footer.
  • Cards fill their container; size them with grid columns.
  • row row-cols-* g-* plus h-100 on each card makes a responsive, equal-height card grid.
  • A row with g-0 inside a card creates a horizontal card.
  • stretched-link makes the whole card clickable, and list-group-flush puts a borderless list inside a card.

Exercise

Build a "Meet our trainers" section with three trainer cards (Ananya, Kabir and Isha). Each card should have the avatar.svg image on top, the trainer's name as the title, their subject as a subtitle, one sentence about them, and a footer showing their experience. On phones show one card per row, from md three per row, all the same height. Make each whole card clickable with a link to #trainer-name.

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Our trainers</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="container py-3">
    <div class="row row-cols-1 row-cols-md-3 g-4">
      <div class="col">
        <div class="card h-100">
          <img src="https://course.ethicscomputer.in/assets/samples/avatar.svg" class="card-img-top" alt="Ananya" width="200" height="200">
          <div class="card-body">
            <h2 class="card-title h5"><a href="#ananya" class="stretched-link text-decoration-none">Ananya</a></h2>
            <h3 class="card-subtitle h6 mb-2 text-body-secondary">Web design</h3>
            <p class="card-text">Teaches HTML, CSS and Bootstrap with real client projects.</p>
          </div>
          <div class="card-footer text-body-secondary">8 years of experience</div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100">
          <img src="https://course.ethicscomputer.in/assets/samples/avatar.svg" class="card-img-top" alt="Kabir" width="200" height="200">
          <div class="card-body">
            <h2 class="card-title h5"><a href="#kabir" class="stretched-link text-decoration-none">Kabir</a></h2>
            <h3 class="card-subtitle h6 mb-2 text-body-secondary">Python</h3>
            <p class="card-text">Loves turning boring office tasks into small scripts.</p>
          </div>
          <div class="card-footer text-body-secondary">5 years of experience</div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100">
          <img src="https://course.ethicscomputer.in/assets/samples/avatar.svg" class="card-img-top" alt="Isha" width="200" height="200">
          <div class="card-body">
            <h2 class="card-title h5"><a href="#isha" class="stretched-link text-decoration-none">Isha</a></h2>
            <h3 class="card-subtitle h6 mb-2 text-body-secondary">Databases</h3>
            <p class="card-text">Explains SQL joins using cricket scorecards.</p>
          </div>
          <div class="card-footer text-body-secondary">6 years of experience</div>
        </div>
      </div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

row-cols-1 row-cols-md-3 g-4 builds the responsive grid, h-100 equalises the heights, and the name link with stretched-link covers each whole card.

Quick Quiz

1. Which class should a card image use so its top corners match the card's rounded corners?

2. Cards in a grid row have different heights. What fixes it?

3. What does stretched-link do?

4. Which Bootstrap 4 class was removed in Bootstrap 5?

Learn Bootstrap with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call