Thumbnail Card
ProMedia card with a configurable image position (top/left/right), four aspect ratios, gradient overlay, badge and content/action projection slots.
Complexity tier: Primitive Presents a value: held to semantic markup and contrast, with its right-to-left and print gaps recorded and the right-to-left debt allowed only to shrink.
import { SvThumbnailCardComponent } from '@styloviz-pro/commerce';Demo & usage
Basic usage
ProUsage example — open the gallery for the full interactive demo.
An interactive demo for this component lives in the gallery.
Open live demoMore examples
Horizontal media card
ProLinked card (whole card navigates)
ProPremium variant — full-bleed cinematic card
ProcardVariant="premium" renders an edge-to-edge image with a dark gradient scrim and inline title/subtitle overlay.
Product variant — price, rating & action footer
ProcardVariant="product" renders a commerce card: star rating, price with an optional compare-at + discount badge, and an add-to-cart footer.
One target per card, and it has to exist
ProThe rule is one sentence: a card has exactly ONE primary target — the title, stretched over the whole card by a ::after overlay — and everything else interactive sits above it on z-10. That is what keeps a nested Add to cart clickable inside a clickable card without nesting one control in another, which is invalid HTML and unusable by keyboard. The corollary is the half that was missing: a card with no title had no target at all, so cardClick could never fire — while hoverable still painted a pointer cursor and a hover lift over the whole thing. cardLabel gives a titleless card a real target with a name only assistive tech sees; without either, the card is not interactive and no longer pretends to be.
When the picture is not there
ProThree different reasons, and they are not interchangeable. A card with no image is a design choice; a card whose image FAILED is a fault — the photo exists and could not be fetched — and rendering the same grey glyph for both told the reader this item simply has no picture. A third, loading, is neither, and an empty frame reads as the first. The failure state re-arms on a new src, so retrying is just handing the card a different URL.
When to use
- Presenting media-led items in a grid: articles, products, videos, files.
- You want a consistent image + title + meta card with optional badge/overlay.
- For dense rows without imagery, a List View is more compact.
Async states
- loading
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
| image | string | '' | Image URL. |
| alt | string | '' | Alt text for the image. |
| title | string | '' | Card title. |
| subtitle | string | '' | Subtitle / meta line (e.g. "June 12 · 8 min read" or "4.2k views · 12 min"). |
| badge | string | '' | Optional badge label. |
| badgeColor | BadgeColor | 'primary' | Badge color (default variant). |
| href | string | '' | Optional link target — makes the card a link. |
| aspectRatio | ThumbnailAspect | '16/9' | Image aspect ratio. |
| imagePosition | ThumbnailPosition | 'top' | Image position relative to content (default variant only). |
| overlay | boolean | false | Gradient overlay on the image (default variant only). |
| hoverable | boolean | true | Hover elevation animation. |
| cardVariant | ThumbnailVariant | 'default' | Card style variant. |
| price | number | null | null | Current price (product variant). |
| compareAt | number | null | null | Original price shown struck through; drives the discount badge. |
| currency | string | 'USD' | ISO 4217 currency code for price formatting. |
| locale | string | 'en-US' | BCP-47 locale for price formatting. |
| rating | number | 0 | Star rating 0–5 with fractional fill (product variant). |
| reviewCount | number | 0 | Review count shown beside the stars (product variant). |
| actionLabel | string | 'Add to cart' | Action-footer button label (product variant). |
| showAction | boolean | true | Show the action-footer button (product variant). |
| cardLabel | string | '' | Accessible name for the whole-card target when the card has no visible title. |
| loading | boolean | false | The image is still being fetched by the host. Renders a neutral placeholder instead of an empty frame. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| cardClick | void | Emitted when the card is clicked. |
| action | void | Emitted when the product action-footer button is pressed. |
Customization & theming
- Position the image with `imagePosition` and pick an `aspectRatio`.
- Add a `badge` with `badgeColor`, optional `overlay` gradient and `hoverable` lift.
- Switch `cardVariant` to `premium` for a full-bleed cinematic card with a gradient scrim and overlaid title/subtitle, or keep the `default` bordered layout.
- Project custom body and action content into the card slots; set `href` to navigate or handle `cardClick`.
- Switch `cardVariant` to `product` for a commerce card with a star rating, price (with compare-at + discount badge) and an add-to-cart action footer.
- `cardLabel` names the whole-card target on a card with no visible title; `hoverable` no longer paints a pointer cursor on a card that has no target at all.
- `loading` renders a neutral placeholder while you fetch the image, and a failed `src` renders a distinct "Image unavailable" state rather than the no-image glyph.
Best practices
- Do: Always set `alt`; when `href` is present the whole card becomes a link.
- Do: Keep aspect ratios uniform across a grid so cards align cleanly.
- Tip: Use the `overlay` gradient only when text sits on top of the image.
- Do: Give a card without a visible title a `cardLabel` if it should be clickable. Without one there is no target, `cardClick` never fires, and the card stops advertising a press it cannot deliver.
- Do: Put every nested control in `svThumbnailActions` or `svThumbnailContent`. Both sit on `z-10`, above the stretched link — anything else you position yourself needs the same.
- Don't: Don't add your own click handler to the card element. The stretched link is the target; a second one competes with it and cannot be reached by keyboard.
- Do: Bind `loading` while you are fetching the image. An empty frame reads as "this item has no picture", which is a different answer.
Accessibility
- Set `href` and the title becomes a real anchor (keyboard-native); without it the title is a button emitting `cardClick`.
- A stretched-link overlay makes the whole card clickable while projected actions/links stay independently reachable above it — one control is never nested inside another.
- A card with no visible title takes its accessible name from `cardLabel`, given to a screen reader only; a card with neither renders no target and no pointer cursor, so it does not advertise a press it cannot deliver.
- A failed image is announced as "Image unavailable" rather than falling back to the same placeholder a card with no picture uses.
- Focus moves a ring around the whole card; images require descriptive `alt`.
Feedback on Thumbnail Card
Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.