Card

A product card composing the Card Image, a title, description, star rating and price. Built on the LUSTER atoms — the embedded image follows the active brand theme. All values pulled directly from the LUSTER Figma component.

AirPods Max
AirPods Max
Spatial audio. Noise cancelled. All-day comfort.
420 reviews
$500 $549
Figma Properties (per theme)
Padding: 16px · Radius: 12px
Title: #24242C (Inter 500 / 20px)
Image bg: #F2EDFF
Rating stars: #EDB000
Price: #794DFF (Inter 700 / 24px)

Component · Card

The product card composes the Card Image (themed), a title + description, a star rating, and the current/old price.

AirPods Max
AirPods Max
Spatial audio. Noise cancelled. All-day comfort.
420 reviews
$500$549
Diamond
AirPods Max
AirPods Max
Spatial audio. Noise cancelled. All-day comfort.
420 reviews
$500$549
Opal
AirPods Max
AirPods Max
Spatial audio. Noise cancelled. All-day comfort.
420 reviews
$500$549
Amber

Design Tokens

Token names mirror the LUSTER Figma variable paths one-to-one. Values shown are the Diamond brand, Light mode defaults (the Figma file's default mode). Other brands (Amber, Opal) and Dark mode resolve to different values via the Color Theme & Component Brand collections.

Token NameFigma VariableDefault Value
--cardImageHeightcard/image/height230px
--cardImageBorderRadiuscard/image/border/radius0px
--cardImageBgColorcard/image/bg/color#F2EDFF
--cardTitleFontColorcard/title/font/color#24242C
--cardTitleMarginBottomcard/title/margin/bottom8px
--cardDescFontColorcard/desc/font/color#62626D
--cardReviewStarsFontColorcard/review/stars/font/color#EDB000
--cardReviewStarsGapcard/reviewStars/gap2px
--cardReviewLabelFontColorcard/review/label/font/color#62626D
--cardReviewsGapcard/reviews/gap8px
--cardNewPriceFontColorcard/newPrice/font/color#794DFF
--cardOldPriceFontColorcard/oldPrice/font/color#62626D
--cardPricesGapcard/prices/gap8px
--cardBodyGapcard/body/gap24px
--cardBodyPaddingXcard/body/padding/x0px
--cardBodyPaddingYTopcard/body/padding/y/top20px
--cardBodyPaddingYBottomcard/body/padding/y/bottom12px
--cardPaddingXcard/padding/x16px
--cardPaddingYcard/padding/y16px
--sectionBgColorsection/bg/color#FFFFFF
--sectionBorderRadiussection/border/radius0px
--sectionShadowColorsection/shadow/color#CECBDC
--sectionShadowOffsetXsection/shadow/offset-x0px
--sectionShadowOffsetYsection/shadow/offset-y0px
--sectionShadowBlursection/shadow/blur0px
--cardTitleContentcard/title/contentAirPods Max
--cardDescContentcard/desc/contentSpatial audio. Noise cancelled. All-day comfort.
--cardReviewLabelContentcard/reviewLabel/content420 reviews
--cardNewPriceContentcard/newPrice/content$500
--cardOldPriceContentcard/oldPrice/content$549
--heading2FontSizetypography/heading-2/font/size20px
--heading2FontLineHeighttypography/heading-2/font/lineHeight24px
--heading2FontWeighttypography/heading-2/font/weight500
--heading1FontSizetypography/heading-1/font/size24px
--heading1FontLineHeighttypography/heading-1/font/lineHeight29px
--heading1FontWeighttypography/heading-1/font/weight700
--caption1FontSizetypography/caption-1/font/size12px
--caption1FontLineHeighttypography/caption-1/font/lineHeight14px
--caption1FontWeighttypography/caption-1/font/weight400
--bodyFontFamilybody/font/familyInter

Usage Guidelines

✓ DO

Keep the image ratio consistent across a grid of cards.

✓ DO

Show the old price struck-through to highlight the discount.

✗ DON'T

Don't crowd the card with more than title, desc, rating and price.

✗ DON'T

Don't hardcode colors — reuse the palette & typography tokens.

Implementation

Values shown are the Diamond brand, Light mode defaults (the Figma file's default mode). Other brands (Amber, Opal) and Dark mode resolve to different values via the Color Theme & Component Brand collections.

import { CardImage } from '@luster/ui';
import './Card.css';

export interface CardProps {
  theme?: 'diamond' | 'dark' | 'amber' | 'opal';
  title: string; description: string;
  rating: number; reviews: number;
  price: string; oldPrice?: string;
}

export const Card = ({ theme, title, description, rating, reviews, price, oldPrice }: CardProps) => (
  <article className="card">
    <div className="card__image"><CardImage theme={theme} alt={title} /></div>
    <h4 className="card__title">{title}</h4>
    <p className="card__desc">{description}</p>
    <div className="card__rating">
      <Stars value={rating} /><span className="card__reviews">{reviews} reviews</span>
    </div>
    <div className="card__price">
      <span className="card__price-now">{price}</span>
      {oldPrice && <span className="card__price-old">{oldPrice}</span>}
    </div>
  </article>
);