Design System — User Interface

Ronix Design System  /  Components  /  Product card

Product card

The densest component in the system and the one that appears most often. It carries a product image, SKU, status labels, title, a three-line specification list, a rating and a compare control — inside 221 px at its narrowest.

Anatomy

Two regions. The media area is a 1:1 square on background/3 (#f0f0f0) holding a cut-out product photograph. The body sits on background/1 with Padding/Small (12 px).

Body order, top to bottom

  • SKU in Caption 1 Strong (12 px), with status labels right-aligned
  • Title in Body 1 Strong — Medium 500, 16/22
  • Specification list in Body 3 — 12/16, three items
  • Rating and Compare, pushed to the foot

Internal gaps are Padding/XXX-Small (4 px); the gap between labels is Padding/XXXX-Small (2 px).

Fig. 1Type=Extra at its 257 px minimum width.
Fig. 2Type=Defualt at its 221 px minimum width. Hover either card to see the Hover state.

States and variants

The component set is a 2×2 matrix: State of Rest or Hover, crossed with Type of Extra or Defualt.

Hover does two things — it draws a 1 px Brand/Stroke/1 border around the whole card, and it lifts the body to background/1/Hover (#f5f5f5). The media area does not change.

There is no pressed or focus variant in the library. For keyboard users the hover treatment should be mirrored on :focus-visible.

VariantMin widthBorderBody fill
State=Rest, Type=Extra257 pxtransparent#ffffff
State=Hover, Type=Extra257 px#a30000#f5f5f5
State=Rest, Type=Defualt221 pxtransparent#ffffff
State=Hover, Type=Defualt221 px#a30000#f5f5f5
Fig. 3Height is content-driven — 377 px and 360 px respectively in the library, but not fixed.

Status labels

Four states ship in the library: New, Hot Sale, Discontinued and Made in Germany, the last carrying a flag glyph.

Labels are 22 px tall, Caption 2 (10/12), with a 2 px radius — the only place in the system that uses Corner radious/2 rather than 4.

Two labels on one card is the practical maximum at Type=Defualt; past that they wrap and push the title down.

New Hot Sale Discontinued Made in Germany 🇩🇪
Fig. 4Labels on a card, in the brand fill.
New Hot Sale Discontinued Made in Germany 🇩🇪
Fig. 5The neutral rendering, used where the card already carries a red element.

Grid and responsive behaviour

Cards sit inside the standard container and step down in count rather than in width. The gap is always Padding/X-Small (8 px).

Below, the live grid follows the same rules — narrow the window and it steps 5 → 4 → 2.

Min width is not a grid constraint

The min width tokens (257 and 221) describe the card used standalone or in a rail. They do not apply inside the grid — the library’s own layouts take cards down to 180 px and 163 px.

Applying min-width to a grid child makes it overflow its column and paint over its neighbour, which silently swallows the hover border on the overlapped edge. Grid cards must be free to shrink.

BreakpointSectionContainerColumnsCard width
Large140013205264
120011405228
Medium9929604240
7687204180
Small5765402270
3583262163
Fig. 6Five across at Large, four at Medium, two at Small. Card width is the container less the gaps, divided by the column count.

Grid or rail?

The library contains a second set of sections where five cards keep their minimum width inside a 326 px container — a total of 1145 px of content in a 326 px frame.

That is not a broken layout; it is a horizontally scrolling rail. Both patterns are legitimate, and they are visually identical until the viewport narrows, so the choice has to be made explicitly in code.

Fig. 8The rail variant: cards hold 221 px and the row scrolls.

PLP card

A category tile, 242×140, with two states — default and hover. It carries an image and a single centred label, nothing else.

Hover draws a dark border rather than the brand red used on the product card.

Fig. 9PLP card, default state. Hover to see the border.
Legacy variableValue
Back Ground / White - Container#ffffff
Back Ground / Light Gray - Base#f2f2f2
Back Ground / Secondary#e5e5e5
Red / Dark Red#bf0000
>358 / Subtitle / Subtitle small14 / 20 Regular
Fig. 10The PLP card’s bindings.

Markup

The whole card is one anchor, so the entire surface is the target rather than the title alone. Compare is a nested control and needs its own handler with preventDefault.

<!-- In a grid: no width modifier, let the column size it -->
<a class="rx-product-card" href="/p/V10200">
  <span class="rx-product-card__media"><img src="…" alt=""></span>
  <span class="rx-product-card__body">
    <span class="rx-product-card__meta">
      <span class="rx-product-card__sku">V10200</span>
      <span class="rx-product-card__labels">
        <span class="rx-label">Hot sale</span>
      </span>
    </span>
    <span class="rx-product-card__title">Heat Gun 2000W</span>
    <ul class="rx-product-card__specs">
      <li>Power 2000W</li>
      <li>2 speed settings</li>
      <li>50-600 &deg;C</li>
    </ul>
    <span class="rx-product-card__footer">
      <span class="rx-rating" aria-label="Rated 4 out of 5">★★★★☆</span>
      <span class="rx-compare">Compare</span>
    </span>
  </span>
</a>