Components
Card
Displays a card with a header, content and footer, plus optional media, a header action and scrolling content.
<div class="card w-full max-w-sm">
<div class="card-header">
<h3 class="card-title">Log in to your account</h3>
<p class="card-description">Enter your email below to log in.</p>
<div class="card-action"><a href="#signup" class="btn btn-link">Sign up</a></div>
</div>
<div class="card-content">
<div class="field">
<label class="field-label" for="card-email">Email</label>
<input class="input" id="card-email" type="email" placeholder="you@example.com" />
</div>
</div>
<div class="card-footer flex-col">
<button class="btn btn-primary w-full">Log in</button>
<button class="btn btn-outline w-full">Log in with SSO</button>
</div>
</div>
Parts#
Every part is optional. .card itself has no padding; the header, content and footer each pad
themselves, so media, tables and lists can run edge to edge.
.card-headerholds.card-titleand.card-description..card-action, inside the header, sits in its top-right corner beside the title and description..card-contentis the body..card-footeris a row for actions, pinned to the bottom of tall cards.
Notifications
You have 3 unread messages.
Your call has been confirmed. Your subscription is expiring soon.
<div class="card w-full max-w-sm">
<div class="card-header">
<h3 class="card-title">Notifications</h3>
<p class="card-description">You have 3 unread messages.</p>
<div class="card-action">
<button class="btn btn-ghost btn-icon btn-sm" aria-label="Settings"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
</div>
</div>
<div class="card-content">
<p class="muted">Your call has been confirmed. Your subscription is expiring soon.</p>
</div>
<div class="card-footer justify-end">
<button class="btn btn-ghost">Dismiss</button>
<button class="btn btn-primary"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg> Mark all as read</button>
</div>
</div>
Image#
.card-image on an <img> (or video, or any media block) runs it edge to edge. As the
first or last child, its outer corners follow the card's.
Weekend in the mountains
Two nights, guided hikes, all meals.
Image at the bottom
Last child, so the bottom corners round.
<div class="card w-full max-w-xs">
<img class="card-image aspect-video" src="../../../images/landscape.svg" alt="Mountains at dusk" />
<div class="card-header pt-5">
<h3 class="card-title">Weekend in the mountains</h3>
<p class="card-description">Two nights, guided hikes, all meals.</p>
<div class="card-action"><span class="badge badge-secondary">New</span></div>
</div>
<div class="card-footer pt-5">
<button class="btn btn-primary w-full">Book now</button>
</div>
</div>
<div class="card w-full max-w-xs">
<div class="card-header pb-5">
<h3 class="card-title">Image at the bottom</h3>
<p class="card-description">Last child, so the bottom corners round.</p>
</div>
<img class="card-image aspect-video" src="../../../images/landscape.svg" alt="Mountains at dusk" />
</div>
Horizontal#
.card-horizontal puts the media beside the text from the sm breakpoint. Wrap the other
parts in .card-body.
Alpine route
12 km, 800 m of climbing.
A full-day loop past three lakes. Start early.
<div class="card card-horizontal w-full max-w-lg">
<img class="card-image aspect-video sm:aspect-auto" src="../../../images/landscape.svg" alt="Mountains at dusk" />
<div class="card-body">
<div class="card-header">
<h3 class="card-title">Alpine route</h3>
<p class="card-description">12 km, 800 m of climbing.</p>
</div>
<div class="card-content"><p class="muted">A full-day loop past three lakes. Start early.</p></div>
<div class="card-footer"><button class="btn btn-outline btn-sm">View map</button></div>
</div>
</div>
Scrolling content#
Add .card-scroll to .card-content to give long content its own scrollbar while the header and
footer stay put. Limit the height on the card (h-80, max-h-96…) or on the content
(max-h-48).
Terms of service
Last updated October 2026.
By using the service you agree to these terms. Please read them carefully.
You are responsible for the content you publish and for keeping your account secure.
We may change the service at any time. We'll tell you about significant changes in advance.
We can suspend accounts that break these terms, after warning you where we reasonably can.
The service is provided as is, without warranties of any kind.
These terms are governed by the laws of the place where we are registered.
<div class="card h-80 w-full max-w-sm">
<div class="card-header">
<h3 class="card-title">Terms of service</h3>
<p class="card-description">Last updated October 2026.</p>
</div>
<div class="card-content card-scroll space-y-3 text-sm text-muted-foreground">
<p>By using the service you agree to these terms. Please read them carefully.</p>
<p>You are responsible for the content you publish and for keeping your account secure.</p>
<p>We may change the service at any time. We'll tell you about significant changes in advance.</p>
<p>We can suspend accounts that break these terms, after warning you where we reasonably can.</p>
<p>The service is provided as is, without warranties of any kind.</p>
<p>These terms are governed by the laws of the place where we are registered.</p>
</div>
<div class="card-footer border-t pt-4 justify-end">
<button class="btn btn-ghost">Decline</button>
<button class="btn btn-primary">Accept</button>
</div>
</div>
Size#
.card-sm uses tighter padding.
Small card
16px padding instead of 24px.
Good for dense dashboards.
<div class="card card-sm w-full max-w-xs">
<div class="card-header">
<h3 class="card-title">Small card</h3>
<p class="card-description">16px padding instead of 24px.</p>
</div>
<div class="card-content"><p class="muted text-sm">Good for dense dashboards.</p></div>
</div>
Clickable card#
Make the whole card an <a> and add .card-link for a hover state.
<a href="/docs/components" class="card card-link w-full max-w-sm">
<div class="card-header pb-6">
<h3 class="card-title flex items-center justify-between">All components <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M5 12h14M12 5l7 7-7 7"/></svg></h3>
<p class="card-description">Browse every component in the library.</p>
</div>
</a>
Loading content with htmx#
Cards make good swap targets. This one fetches its body from the server:
Server message
Fetched with hx-get.
<div class="card w-full max-w-sm">
<div class="card-header">
<h3 class="card-title">Server message</h3>
<p class="card-description">Fetched with hx-get.</p>
</div>
<div class="card-content" id="card-body">
<button class="btn btn-outline btn-sm" hx-get="/api/hello" hx-target="#card-body">Load</button>
</div>
</div>
Reference#
| Class | Description |
|---|---|
.card | Container: border, surface colour, radius and shadow. |
.card-header | Top section, padded on three sides. |
.card-title | Heading text. |
.card-description | Muted supporting text. |
.card-action | Inside the header: top-right slot beside the title and description. |
.card-content | Main body, padded on all sides. |
.card-scroll | On .card-content: scrolls on its own when the card or content has a height limit. |
.card-footer | Bottom row for actions; pinned to the bottom of tall cards. |
.card-image | Edge-to-edge media; outer corners follow the card's. |
.card-horizontal | Media beside the content from the sm breakpoint. Wrap the parts in .card-body. |
.card-sm | Tighter padding. |
.card-link | Hover style for cards that are links. |