JavaScript Card
@lemonadejs/card · ✓ 24 contract checks · framework-agnostic · zero dependencies
<Card /> — a content surface block (LemonadeJS v6)
The classic card sections (header / media / content / actions)
collapsed into one contract-driven block. Every section is a branch:
it only exists in the DOM when its props are set — the media image
when image is set, the header when any of avatar/title/subtitle is
set, the action row when actions has entries. Children always
render in the content area, after the content text.
Two variants through data-variant: ” (elevated — subtle shadow, the
default) and ‘outlined’ (1px border, no shadow). clickable makes
the whole card an interactive surface (hover lift + onclick); action
buttons stop propagation so their clicks never double-fire the card.
Example
import { html } from 'lemonadejs';
import Card from '@lemonadejs/card';
const App = (props, { state }) => {
const status = state('Not saved');
const actions = [
{ label: 'Share', onclick: () => (status.value = 'Link copied') },
{ label: 'Save', onclick: () => (status.value = 'Saved to your trips') },
];
return html`<div style="display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-start;">
<div style="width: 300px;">
<${Card} image="https://picsum.photos/seed/lisbon/600/340"
title="Lisbon weekend" subtitle="18 to 20 April 2026"
content="Two nights in Alfama, a day trip to Sintra and pastel de nata on every corner."
actions="${actions}" />
</div>
<div style="width: 300px;">
<${Card} variant="outlined" clickable title="Porto extension" subtitle="Optional, 1 night"
content="Click anywhere on this card." onclick="${() => (status.value = 'Porto added to the plan')}" />
<p>Status: <b>${status}</b></p>
</div>
</div>`;
};Installation
npm install @lemonadejs/card
import Card from '@lemonadejs/card';
import '@lemonadejs/card/style.css';
Three deployment forms, one component:
html`<${Card} />` // by value (no registration)
setComponents({ Card }); // then <Card /> by name anywhere
createWebComponent(Card); // <lm-card> in plain HTML/any framework
Props
Every declared prop arrives as a live state — pass a value for a snapshot or a state for a two-way live wire. Attribute strings are coerced to the declared type.
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | '' | header title line |
subtitle | string | '' | muted line under the title |
image | string | '' | media url, top image (object-fit: cover) |
imageheight | number | 180 | media height in px |
imagealt | string | '' | media image alt text (” = decorative) |
avatar | string | '' | small round img beside the header titles |
avataralt | string | '' | avatar alt text (” = decorative) |
content | string | '' | body text (children render after it) |
actions | array | — | CardAction[] — footer buttons, right-aligned |
variant | string | '' | ” = elevated |
clickable | boolean | false | whole card hover lift + onclick |
Events
All event names are lowercase (the platform convention — LJS-305 warns otherwise).
onclick— fires when a clickable card is clicked
Styling
All classes follow the lm-card-* convention; visual variants are data-*
attributes on the root. Override freely — there is no styling engine to fight.
Contract
The machine-readable schema ships with the package:
import contract from '@lemonadejs/card/contract.json';
verify.json carries the conformance proof produced by verify(Card).
Looking for the v5 plugin? See the archived v5 documentation.