Lesson 6 of 12

Bootstrap Cards

A card is a bordered box that groups related content: a product, a blog post, a team member, a tour package. Bootstrap cards are one of the most used components because they are flexible. A card can hold an image, a title, text, links, a list or buttons, in almost any combination, and cards line up nicely in the grid.

The parts of a card

A card is built from a few nested classes. Only card is required; the rest are optional pieces you add as needed.

ClassPurpose
cardThe outer box: border, rounded corners and a flex column layout
card-bodyThe padded area for the main content
card-title, card-subtitleHeadings with suitable spacing
card-textParagraphs inside the body (removes the extra bottom margin on the last one)
card-img-top, card-img-bottomAn image that fills the card width with matching rounded corners
card-header, card-footerShaded strips above or below the body
card-linkLinks placed side by side at the bottom of the body
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A basic card</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
  <div class="card" style="max-width: 20rem;">
    <svg class="card-img-top" width="100%" height="150" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Illustration of Marina Beach at sunrise" preserveAspectRatio="xMidYMid slice"><rect width="100%" height="100%" fill="#0d6efd"/><circle cx="80%" cy="35%" r="22" fill="#ffc107"/></svg>
    <div class="card-body">
      <h2 class="card-title h5">Marina Beach walk</h2>
      <h3 class="card-subtitle h6 mb-2 text-body-secondary">Chennai · 2 hours</h3>
      <p class="card-text">An early-morning walk along one of the longest urban beaches in India, ending with filter coffee.</p>
      <a href="#" class="btn btn-primary">See details</a>
    </div>
  </div>
</div>
</body>
</html>

Bootstrap cards have no fixed width. A card stretches to fill its parent, so you normally control the width with the grid or a utility rather than on the card itself. Here a small inline max-width keeps the single card narrow. The coloured image is a simple inline SVG so the example works offline; on a real site you would use <img src="…" class="card-img-top" alt="…"> with a meaningful alt text.

Headers, footers, lists and colours

A card-header works well for a category or a step label, and a card-footer for dates, prices or actions. You can also drop a list group straight into a card with list-group list-group-flush, which removes the outer borders so the list blends into the card. To colour a whole card, use text-bg-primary and friends on the card element, or just a coloured border such as border-success.

Card grids with equal heights

To show several Bootstrap cards, put them in the grid. The neatest way is row-cols-* on the row with a col around each card. Add h-100 to each card so all cards in a row have the same height, even when one has more text. Because a card is a flex column, a footer always sits at the bottom.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Equal-height card grid</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
  <h1 class="h3 mb-3">Weekend trips from Bengaluru</h1>
  <div class="row row-cols-1 row-cols-md-3 g-4">
    <div class="col">
      <div class="card h-100">
        <svg class="card-img-top" width="100%" height="150" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Green hills of Nandi" preserveAspectRatio="xMidYMid slice"><rect width="100%" height="100%" fill="#198754"/><circle cx="80%" cy="35%" r="22" fill="#d1e7dd"/></svg>
        <div class="card-body">
          <h2 class="card-title h5">Nandi Hills</h2>
          <p class="card-text">Sunrise views above the clouds, about 60 km away.</p>
        </div>
        <div class="card-footer text-body-secondary">Day trip</div>
      </div>
    </div>
    <div class="col">
      <div class="card h-100">
        <svg class="card-img-top" width="100%" height="150" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Old stone ruins at Hampi" preserveAspectRatio="xMidYMid slice"><rect width="100%" height="100%" fill="#fd7e14"/><circle cx="80%" cy="35%" r="22" fill="#fff3cd"/></svg>
        <div class="card-body">
          <h2 class="card-title h5">Hampi</h2>
          <p class="card-text">Boulder landscapes, the Vittala temple and coracle rides on the Tungabhadra. Plan at least two days to see the main sites without rushing.</p>
        </div>
        <div class="card-footer text-body-secondary">2–3 days</div>
      </div>
    </div>
    <div class="col">
      <div class="card h-100 border-primary">
        <div class="card-header text-bg-primary">Popular</div>
        <div class="card-body">
          <h2 class="card-title h5">Mysuru</h2>
          <p class="card-text">The palace, Chamundi Hill and silk shopping.</p>
        </div>
        <ul class="list-group list-group-flush">
          <li class="list-group-item">Mysore Palace</li>
          <li class="list-group-item">Brindavan Gardens</li>
        </ul>
        <div class="card-footer text-body-secondary">Weekend</div>
      </div>
    </div>
  </div>
</div>
</body>
</html>

In the preview the three cards sit side by side and are all as tall as the tallest one. On a phone, row-cols-1 stacks them. Try deleting h-100 from one card to see the difference.

Tip: Bootstrap also has card-group, which joins cards edge to edge with no gaps, and the Masonry layout used by some sites needs an extra JavaScript library. For most designs, the grid with row-cols-* and g-* is the simplest and most flexible option. See Bootstrap Grid System for a refresher.

Horizontal cards and clickable cards

For a list of articles or search results, an image beside the text often reads better. Put a row g-0 inside the card, with the image in one column and the card-body in another. Use rounded-start on the image so only its left corners are rounded.

To make the whole card clickable, add stretched-link to the main link inside it. Bootstrap stretches an invisible layer from that link over its nearest positioned parent. The card is already position: relative, so the whole card becomes the click area while the link text remains the accessible name.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Horizontal, clickable card</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
  <div class="card mb-3" style="max-width: 560px;">
    <div class="row g-0">
      <div class="col-4">
        <svg class="img-fluid rounded-start" width="100%" height="160" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Plate of Chettinad chicken" preserveAspectRatio="xMidYMid slice"><rect width="100%" height="100%" fill="#dc3545"/><circle cx="80%" cy="35%" r="22" fill="#f8d7da"/></svg>
      </div>
      <div class="col-8">
        <div class="card-body">
          <h2 class="card-title h5">A beginner's guide to Chettinad cooking</h2>
          <p class="card-text">Kalpasi, marathi mokku and fresh pepper give Karaikudi dishes their deep flavour.</p>
          <a href="#" class="stretched-link">Read the article</a>
          <p class="card-text mt-2"><small class="text-body-secondary">8 min read</small></p>
        </div>
      </div>
    </div>
  </div>
  <p id="msg" class="text-body-secondary">Click anywhere on the card.</p>
</div>
<script>
document.querySelector('.stretched-link').addEventListener('click', (event) => {
  event.preventDefault();
  document.getElementById('msg').textContent = 'The card link was clicked.';
});
</script>
</body>
</html>

Watch out: Do not put other buttons or links inside a card that uses stretched-link. The stretched layer sits on top of them and swallows their clicks. If a card needs several actions, skip stretched-link and give each action its own clear button.

Design tips for Bootstrap cards

  • Use a real heading element for the card title (h2, h3…) so screen reader users can jump between cards. Use h5 as a class to control the size.
  • Keep each card about one thing, with one main action.
  • Give every image a meaningful alt text, or alt="" if it is purely decorative.
  • Keep card text short. Cards are for scanning; the detail page is for reading.

Further reading

Key takeaways

  • A card is card plus optional card-body, card-title, card-text, images, header and footer.
  • Cards fill their parent, so control width with the grid.
  • Use row row-cols-1 row-cols-md-3 g-4 and h-100 on cards for an equal-height grid.
  • Horizontal cards use row g-0 inside the card with rounded-start on the image.
  • stretched-link makes the whole card clickable but should not be mixed with other links in the card.

Quick quiz

Check what you learned – pick an answer.

1. Which class makes all cards in a grid row the same height?

2. Where should you usually set the width of a card?

3. What does stretched-link do?

Practice exercise

Create a team section with three member cards in a responsive grid (one per row on phones, three from 768px). Each card has a body with the person's name as a heading, their role in muted text, a short line about them, and a footer with an outline "Contact" button. Make all cards equal height.

Show a hint

Use row row-cols-1 row-cols-md-3 g-4, col, and card h-100.

Show the solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Team cards</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-4">
  <h1 class="h3 mb-3">Our team</h1>
  <div class="row row-cols-1 row-cols-md-3 g-4">
    <div class="col">
      <div class="card h-100">
        <div class="card-body">
          <h2 class="card-title h5">Ananya Krishnan</h2>
          <p class="card-subtitle mb-2 text-body-secondary">UX designer</p>
          <p class="card-text">Runs user interviews and turns them into simple flows.</p>
        </div>
        <div class="card-footer"><button type="button" class="btn btn-outline-primary btn-sm">Contact</button></div>
      </div>
    </div>
    <div class="col">
      <div class="card h-100">
        <div class="card-body">
          <h2 class="card-title h5">Rahul Menon</h2>
          <p class="card-subtitle mb-2 text-body-secondary">Front-end developer</p>
          <p class="card-text">Builds accessible interfaces with HTML, CSS and JavaScript, and reviews every pull request for keyboard support.</p>
        </div>
        <div class="card-footer"><button type="button" class="btn btn-outline-primary btn-sm">Contact</button></div>
      </div>
    </div>
    <div class="col">
      <div class="card h-100">
        <div class="card-body">
          <h2 class="card-title h5">Fathima Begum</h2>
          <p class="card-subtitle mb-2 text-body-secondary">Content writer</p>
          <p class="card-text">Writes clear help pages in English and Tamil.</p>
        </div>
        <div class="card-footer"><button type="button" class="btn btn-outline-primary btn-sm">Contact</button></div>
      </div>
    </div>
  </div>
</div>
</body>
</html>

Progress is saved in this browser only.