Card
A boundary around one subject, picture, heading, context and the actions that belong to them.
A card is a boundary: it groups one subject's picture, heading, sentence of context and actions on a surface that says these belong together, so a page can show several of them without inventing a layout each time.
It is not a layout primitive, the arrangement inside it comes from Stack and Grid, and the
card supplies the surface, the spacing scale and, when it is interactive, the semantics. Nor is
it a container for other cards: the surface is drawn once, by the outer one. Its siblings state
one fact each: Badge and Chip label, Avatar represents, and a card is where all of them
are put.
Usage
import { Card } from "@asheeui/web";
<Card title="Invoice INV-1041" description="Northwind Traders · due 31 March">
£4,280.00 outstanding across twelve line items.
</Card>
children is the body, and body states it explicitly when the card's content is not the
element's children. header sits above the title, title and description are rendered for
you, and footer sits at the bottom of the content column, which is where a price and its
actions usually go.
Pictures
An image has three placements. top and bottom draw it outside the padded content, so it is
full-bleed and clipped by the card's radius; background draws it under the content instead,
for a card that is a cover rather than a row.
In the image object, ratio locks the frame the picture is fitted into and fit decides how it
fills that frame, video and cover when nothing states otherwise, and both resolve through the
cascade, so components.card.image.ratio retunes every card at once. loading resolves the same
way and falls back to lazy. loading and priority that the picture's own component states are
forwarded as given: the card does not overrule a framework's loader.
image.component and image.componentProps keep a framework's own image working inside the
card, the intrinsic size, the loader, the allowed host, and link.component does the same for
the element the whole card renders as. Both are the framework's one seam:
links and substitution.
Cards that go somewhere
A card becomes interactive when link or onClick is given, or when isClickable says so. A
link makes the root the link itself rather than a handler on a div, so it is announced as a
link and opens like one, and link.component renders a router's own link in its place. An
onClick without a link keeps the card a div but gives it button semantics, so
Enter and Space both work.
link.componentProps is spread onto the card's root last, so its href and its own onClick win
over the props the framework passes, and the card's onClick still runs beside the link's.
className is the one exception: it is merged into the card's classes through cn rather than
spread last, because spreading it last would replace the surface the card drew. isDisabled dims the
card, refuses the press and takes it out of the tab order: an unavailable card is drawn but
cannot be reached, the opposite of a disabled Button, which stays focusable so a reader can
find out why it will not press. A card that renders a real link stays reachable even when
isClickable is false, the card's own affordance and the link are separate things, and a
destination should not become unreachable because a prop described the surface.
Props
size, animate and image.position are registered as md, true and top, so density, the
press animation and the default picture placement resolve from the instance or from
components.card. variant and radius are not registered: radius resolves from the
application's defaultRadius, the framework's own is xs, so a card is only slightly rounded
until the product rounds more, and variant resolves from the application's defaultVariant
through a map onto the four surfaces a card draws, so solid becomes elevated and faded or
underlined land on the resting bordered. A page with no configuration gets a bordered card
on the application's radius.
image.ratio and image.fit resolve from the instance, then components.card.image, then the
video and cover fallbacks; image.loading resolves the same way. titleAs changes the
heading level and is instance-only. link, isClickable, isDisabled, the four content slots
and the image's src, alt and component are instance-only too, because they state this
card's subject rather than the design's.
Accessibility
titleis rendered as a level-three heading by default, so a card belongs under a level-two heading;titleAsstates the level when the card sits somewhere else in the outline.- A card with
onClickrendersrole="button"and answers Enter and Space. A card with alinkrenders the link element instead and keeps that element's own activation, so it is announced as a link, opens in a new tab, and its destination can be copied. isDisabledsetsaria-disabled, dims the card, removes it from the pointer (pointer-events-none) and from the tab order (tabindex="-1").- The picture is the only part with alternative text: state
image.alt, or pass an empty one for a decorative cover whose title already says what it is.