ComponentsLumos 0.0.1UpdatedOpen component
Card
A self-contained block (eyebrow, heading, text and a button) in three arrangements.
Card takes its content as props rather than slots, which is what makes a grid of them consistent: every card gets the same heading size, the same button style and the same internal spacing, whatever is in it.
<Grid xsmall={1} medium={3}>
<Card heading="Default" text="Text only." buttonLabel="Read more" buttonHref="#" />
<Card variant="cover" image={cover} heading="Cover" buttonLabel="Read more" buttonHref="#" />
<Card variant="stacked" image={cover} heading="Stacked" buttonLabel="Read more" buttonHref="#" />
</Grid>The three variants in a three-column grid.
Props
Content
| Prop | Type | Default | What it does |
|---|---|---|---|
render | boolean | true | Set to false to skip this component and everything inside it. |
eyebrow | string | None | A small line above the heading. Nothing renders without one. |
heading | string | None | The card's title. |
headingTag | "h1"–"h6" | "h3" | The heading level, for the page outline. Every card heading is the same size whatever the level. |
text | string | None | Body copy under the heading. |
buttonLabel | string | None | The closing button's label. No button renders without one. |
buttonHref | string | None | Where the button leads. Left out, it renders as a plain button. |
Appearance
| Prop | Type | Default | What it does |
|---|---|---|---|
variant | "default" | "cover" | "stacked" | "default" | default is text only. cover fills the card with the image and puts the text over it. stacked puts the image above the text, bleeding to the edges. |
image | ImageMetadata | string | None | An imported asset, a remote URL, or a path to a file in public/. Only on cover and stacked. |
imageAlt | string | None | Leave unset on a decorative image: it renders alt="". |
theme | "inherit" | "light" | "dark" | "brand" | "invert" | "inherit" | Colors the card carries with it, whatever section it sits in. Not available on stacked, which has no surface of its own. |
The button matches the variant
Each variant closes with the button style that suits it (primary on a cover card, secondary on a default one, a link on a stacked one), so a mixed set still reads as one system. You do not choose it.
Buttons line up across a row
In a grid of cards with different amounts of text, every button still sits on the card's floor. That is handled by the framework, not by you setting a height.
When props are not enough
Card is deliberately narrow. When you need something it does not do (a price, a rating, a second button), build your own component rather than adding props to this one. Use ContentWrapper and the text components inside it and you will still be inside the system.
Lists of cards
When cards are a list of things, say so in the markup: a <ul> around them and role="listitem" on each. A screen reader then announces how many there are before reading them.
<Grid xsmall={1} medium={3}>
<ul class="display-contents">
{posts.map((post) => (
<Card role="listitem" heading={post.title} text={post.excerpt} />
))}
</ul>
</Grid>