A card with an image on top and a title, subtitle and meta row below, for artwork lists, artist tiles and booking previews. It composes `atoms.card` with no padding, so fill, border and corners are Card's.

pnpm add @behivetech/molecules.image-card

You are viewing Image Card v0.2.0, snapshotted 2026-11-09. The latest is v0.2.2. Go to the latest →

A card with an image on top and a title, subtitle and meta row below, for artwork lists, artist tiles and booking previews. It composes atoms.card with no padding, so fill, border and corners are Card's.

Usage

1import { ImageCard } from "@behivetech/molecules.image-card";
2
3<ImageCard
4 href="/art/blue-hour"
5 media={
6 <img src="/blue-hour.jpg" alt="Blue hour on the porch, oil on canvas" />
7 }
8 title="Blue hour on the porch"
9 subtitle="Lena Park"
10 meta="$480.00"
11/>;

The ```jsx block above runs live on the docs site. Imports are stripped and every registry export is in scope, so you can compose with other components too.

Behaviour

  • With href, the whole card is one link named by the title. Pass linkComponent (for example next/link) for client-side routing. Keep meta non-interactive: the link covers the card. Without href the card is static, with no hover or focus stop.
  • The media box holds its aspectRatio (4/5, 1/1 or 3/2) before the image loads. Give the image its descriptive alt.
  • If an <img> in media fails to load, including before hydration, the box shows an image icon at the same ratio. The icon is labelled unavailableLabel ("Image unavailable") followed by the image's alt text. A new src on the image clears the failure, as long as media is the image element itself (an <img> or next/image).
  • The card reads src from the root element of media only. Once the image fails it is replaced by the icon and can no longer be read, so a wrapper without a src prop, or a <picture>, never clears its failure. When media is one of those, give the card a key that changes with the image (for example key={artwork.id}).
  • The title clamps at two lines and the subtitle at one. In a grid row the card fills the row's height and meta sits on its bottom edge.
  • The hover glow reads --brand-glow-violet from @behivetech/cms.base-styles; it is transparent in Light. Glow is on the card, never on text.

Properties

ImageCard props

PropTypeDefaultDescription
media*ReactNode—The image, or any node that holds one (`next/image` with `fill` works). Give the image its descriptive `alt`. If an `<img>` inside fails to load, including before hydration, the media box swaps it for an image icon at the same aspect ratio, labelled with `unavailableLabel` and the alt text. A new `src` on the image clears the failure, but only when `media` is the image element itself (an `<img>` or `next/image`). If `media` is a wrapper or a `<picture>`, give the card a `key` that changes with the image.
title*ReactNode—Card title, clamped at two lines. It names the link when `href` is set.
aspectRatio"4/5" | "1/1" | "3/2"4/5Aspect ratio of the media box, held before the image loads. Defaults to `4/5`.
classNamestring—Additional class names to merge with the component root element
headingLevel1 | 2 | 3 | 4 | 5 | 63Which heading tag (`h1`-`h6`) wraps the title. Defaults to `3`.
hrefstring—Makes the whole card one link, named by the title. Omit for a static card with no hover and no focus stop.
linkComponentElementTypeaComponent that renders the link, for client-side routing (pass `next/link`). Receives `href` and `className`. Defaults to a plain `a`.
metaReactNode—Optional row on the card's bottom edge (a price, a status badge); keep it non-interactive
subtitleReactNode—Optional line under the title, clamped at one line
unavailableLabelstringImage unavailableLabel for the failed-image fallback, read before the image's alt text. Defaults to "Image unavailable"; pass your translation.

Also accepts the native attributes of its root element (className, aria-*, event handlers, …).