RZREDZ.UI

Cards

A card is a bordered region of a screen: a header with its title and actions, a body, a footer. It is a region - the width prefixes inside it measure the card, not the window.

Examples

A card that is a section of the screen is a <section> named by its heading. The header holds an icon, the title and whatever belongs to it; the footer holds the card's actions.

Price

in the base currency THB

Adults 2,500 · children 1,900 · under four free.

The visitor's currency is an estimate.

<section class="card" aria-labelledby="card-basic-title">
	<div class="card-header"><i class="bi bi-cash-coin" aria-hidden="true"></i><h2 id="card-basic-title">Price</h2><span class="text-muted fs-12">in the base currency THB</span></div>
	<div class="card-body vstack gap-8">
		<p>Adults 2,500 · children 1,900 · under four free.</p>
		<p class="text-muted">The visitor's currency is an estimate.</p>
	</div>
	<div class="card-footer justify-content-end">
		<button class="btn" type="button">Cancel</button>
		<button class="btn btn-primary" type="button">Save</button>
	</div>
</section>

A product tints the head of every card with --redz-card-header-bg.

Images

card-img-top and card-img-bottom round the image with the card's corners; card-img-overlay lays the card's words over a card-img. A stretched-link makes the whole card its link.

A lagoon under green hills

North Bay by speedboat

From 2 500 THB · a day

The emerald lake

<div class="grid md:cols-2 gap-16">
	<section class="card" aria-labelledby="card-images-title">
		<img class="card-img-top ratio-16x9" src="img/lagoon.svg" alt="A lagoon under green hills">
		<div class="card-body vstack gap-4">
			<h2 class="fs-16" id="card-images-title"><a class="stretched-link" href="#card-images">North Bay by speedboat</a></h2>
			<p class="text-muted mb-0">From 2 500 THB · a day</p>
		</div>
	</section>
	<section class="card" aria-labelledby="card-overlay-title">
		<img class="card-img ratio-16x9" src="img/lagoon.svg" alt="">
		<div class="card-img-overlay vstack justify-content-end">
			<h2 class="fs-16" id="card-overlay-title">The emerald lake</h2>
		</div>
	</section>
</div>

Tabs on a card

A nav placed straight in the card lines up with the header's padding.

North Bay

A day at sea: snorkelling at two reefs, lunch on the boat.

<section class="card" aria-labelledby="card-tabs-title">
	<div class="card-header"><h2 id="card-tabs-title">North Bay</h2></div>
	<div class="nav nav-underline" role="tablist" aria-label="North Bay">
		<button class="nav-link" type="button" role="tab" id="card-tabs-1" aria-selected="true" aria-controls="card-tabs-panel-1">Details</button>
		<button class="nav-link" type="button" role="tab" id="card-tabs-2" aria-selected="false" aria-controls="card-tabs-panel-2">Prices</button>
	</div>
	<div class="card-body" id="card-tabs-panel-1" role="tabpanel" aria-labelledby="card-tabs-1" tabindex="0"><p>A day at sea: snorkelling at two reefs, lunch on the boat.</p></div>
	<div class="card-body" id="card-tabs-panel-2" role="tabpanel" aria-labelledby="card-tabs-2" tabindex="0" hidden><p>Adults 2,500 · children 1,900.</p></div>
</section>

A grid of cards

The parent sets the grid; each card measures itself. Under 576 px of the region the cards stack.

Bookings

128

this week

Revenue

312,400 THB

this week

<div class="grid sm:cols-2 gap-16">
	<section class="card" aria-labelledby="card-grid-a"><div class="card-header"><h2 id="card-grid-a">Bookings</h2></div><div class="card-body"><p class="fs-24 fw-600 tabular-nums">128</p><p class="text-muted">this week</p></div></section>
	<section class="card" aria-labelledby="card-grid-b"><div class="card-header"><h2 id="card-grid-b">Revenue</h2></div><div class="card-body"><p class="fs-24 fw-600 tabular-nums">312,400 THB</p><p class="text-muted">this week</p></div></section>
</div>

A body that scrolls

card-scroll with a height - max-h-*, from 160 to 640 px - keeps the card's header and footer in view and scrolls its body between them, as a dialog does: a list of tickets, a thread above its reply box.

Tickets

<section class="card card-scroll max-h-240" aria-labelledby="card-scrolling-title">
	<div class="card-header"><h2 id="card-scrolling-title">Tickets</h2></div>
	<div class="card-body" tabindex="0" role="region" aria-labelledby="card-scrolling-title">
		<div class="list-group list-group-flush">
			<button class="list-group-item list-group-item-action" type="button" aria-current="true">The booking page shows the wrong price</button>
			<button class="list-group-item list-group-item-action" type="button">A new language for the site</button>
			<button class="list-group-item list-group-item-action" type="button">The invoice for October</button>
			<button class="list-group-item list-group-item-action" type="button">Photos do not upload from a phone</button>
			<button class="list-group-item list-group-item-action" type="button">Change the site's address</button>
			<button class="list-group-item list-group-item-action" type="button">Two owners for one site</button>
		</div>
	</div>
	<div class="card-footer"><button class="btn btn-sm" type="button"><i class="bi bi-plus-lg" aria-hidden="true"></i>New ticket</button></div>
</section>

A state on its edge

The utility edge-top-{tone} draws a 3 px line of a state on a card's top edge, instead of coloring its frame; edge-start-{tone} does it on the start edge of a row. The words still say the state.

Dispatcher

Running, last beat 4 s ago

Mail queue

Late by 6 minutes

  • Online bookingCalendar, deposits, reminders490 THB
  • Site and hostingIncluded in every planIncluded
<div class="grid sm:cols-2 gap-16">
	<section class="card edge-top-success" aria-labelledby="card-edge-a"><div class="card-header"><h2 id="card-edge-a">Dispatcher</h2></div><div class="card-body"><p>Running, last beat 4 s ago</p></div></section>
	<section class="card edge-top-warning" aria-labelledby="card-edge-b"><div class="card-header"><h2 id="card-edge-b">Mail queue</h2></div><div class="card-body"><p>Late by 6 minutes</p></div></section>
</div>
<ul class="list-group" aria-label="Plan items">
	<li class="list-group-item hstack gap-12 edge-start-primary"><span>Online booking<span class="d-block fs-12 text-muted">Calendar, deposits, reminders</span></span><span class="ms-auto tabular-nums">490 THB</span></li>
	<li class="list-group-item hstack gap-12 edge-start-success bg-page"><span>Site and hosting<span class="d-block fs-12 text-muted">Included in every plan</span></span><span class="ms-auto text-muted">Included</span></li>
</ul>

For a category instead of a state - a site, a team, a kind of job - edge-top-chart-1 to -8 and edge-start-chart-1 to -8 take the charts' eight colors, so a row matches its series in a chart.

  • Main Island
  • South Bay
  • West Bay
<ul class="list-group" aria-label="Sites">
	<li class="list-group-item edge-start-chart-1">Main Island</li>
	<li class="list-group-item edge-start-chart-2">South Bay</li>
	<li class="list-group-item edge-start-chart-3">West Bay</li>
</ul>

Accessibility

  • A card that is a part of the page is a <section> with aria-labelledby pointing at its heading; a card in a list of cards is an <article> or a list item.
  • A card has no outer margin: the gap between cards belongs to their parent.
  • A card being refreshed in place turns busy with REDZ.ui.busy(card, promise) - see Busy.

Tokens

From css/components/card.css, which declares no custom property of its own.

It reads the theme's --redz-border, --redz-radius-12, --redz-bg, --redz-space-16, --redz-space-8, --redz-space-12, --redz-card-header-bg, --redz-text-muted.

From Bootstrap 5.3

Bootstrap 5.3REDZ.UIChangeNote
card-group-reviewgrid with gap-16
card-header-pills-reviewa nav straight in the card
card-header-tabs-reviewa nav straight in the card
card-link-reviewa heading and paragraphs in card-body
card-subtitle-reviewa heading and paragraphs in card-body
card-text-reviewa heading and paragraphs in card-body
card-title-reviewa heading and paragraphs in card-body