Card
Generic raised surface container with optional header/body/footer sections. Use for grouping related content on a page. For draggable-looking Kanban cards use the .issue-card subcomponent instead — it is an independent root, not a .card variant.
Root: .card on <div>, <section>, <article>
Example
<div class="card"><div class="card-header">Sprint 14</div><div class="card-body">Content</div></div>
Authoring source
<lz-issue-card type="bug" key="LOZ-14">
Login page throws redirect loop on expired session
<lz-avatar slot="meta" size="sm">DK</lz-avatar>
</lz-issue-card>
Expands to
<div class="issue-card" data-lz="issue-card" data-lz-version="0.1.0">
<div class="issue-card-summary">
Login page throws redirect loop on expired session
</div>
<div class="issue-card-meta">
<span class="issue-type issue-type-bug" role="img" aria-label="bug"></span>
<span class="issue-key">LOZ-14</span>
<span class="avatar avatar-sm" data-lz="avatar" data-lz-version="0.1.0">DK</span>
</div>
</div>
Authoring tags are macro-expanded to the canonical HTML above at build time (Vite plugin or lz-expand CLI) — the shipped artifact has no runtime.
Contract
Structure
| Selector | Required | Description |
|---|---|---|
.card-header | optional | Optional heading strip with bottom separator. |
.card-body | optional | Padded content region; use for the main content. |
.card-footer | optional | Optional footer strip with top separator. |
Accessibility
Cards are non-interactive surfaces; if the whole card should be clickable, put a single <a> inside rather than click handlers on the div. Use a real heading element inside .card-header.
Nesting
Allowed in:
page contentgrid/flex layouts
Never inside (or containing):
.card
Subcomponents
Issue-card
A single issue on a Kanban board: summary text plus a meta row of issue-type icon, key, badge/lozenge, and avatar. Lives inside .board-column-cards; consecutive issue-cards space themselves 8px apart.
Root: .issue-card on <div>
Example
<div class="issue-card"><div class="issue-card-summary">Fix login redirect loop</div><div class="issue-card-meta"><span class="issue-type issue-type-bug" aria-label="Bug"></span><span class="issue-key">PROJ-42</span><span class="badge">3</span><span class="avatar avatar-sm">JC</span></div></div>
Structure
| Selector | Required | Description |
|---|---|---|
.issue-card-summary | required | The issue title; wraps and word-breaks. |
.issue-card-meta | optional | Flex meta row (8px gap). Order matters visually: .issue-type first, then .issue-key, then badges/lozenges; put the .avatar last — it right-aligns via margin-left:auto. |
.issue-card-meta > .issue-key | optional | The issue identifier (e.g. LOZ-42); truncates. |
Accessibility
The SCSS gives .issue-card cursor:pointer but the demo markup is a plain div — if a card opens the issue, make it (or its summary) a real link/button so it is keyboard-operable. Inner .issue-type icons need a text alternative (see issue-type).
Nesting
Allowed in:
.board-column-cards
Never inside (or containing):
.issue-card.card
Issue-type
16px colored square standing in for an issue-type glyph icon (story/bug/task/epic). Fixed categorical colors, deliberately not accent-driven. Used in .issue-card-meta, table cells, and inline next to titles.
Root: .issue-type on <span>
Example
<span class="issue-type issue-type-story" aria-label="Story"></span>
Variants & modifiers
| Class | Axis | Rules |
|---|---|---|
issue-type-story | type | one required · exclusive |
issue-type-bug | type | one required · exclusive |
issue-type-task | type | one required · exclusive |
issue-type-epic | type | one required · exclusive |
Accessibility
The square is color-only with no text content: give it aria-label ("Bug", "Story"...) when the type is not stated in nearby text, or aria-hidden="true" when it is purely decorative next to visible text.
Nesting
Allowed in:
.issue-card-metatable cells.flag-iconinline before titles
Never inside (or containing):
.issue-type