Design with AI
React for Designers and PMs

Coffee cards grid

A React component that displays a grid of gift cards by mapping over an array of objects.

LLM Written
Human Reviewed

Output

Starbucks

A 'Giftzy Latte'

New

One venti Caffe Latte and one Double Chocolate Brownie from Starbucks.

$11.07
Cold Stone

Berry Good Combo

A medium Berry Berry Berry Good ice cream with waffle cone and topping.

$8.49
The Cheesecake Factory

Slice of Heaven

New

One slice of Original Cheesecake with a fresh strawberry topping.

$9.95
Crumbl

Cookie Party Box

A four-pack of weekly rotating flavors from Crumbl Cookies.

$15.99
Dunkin'

Morning Kickstart

New

A medium iced coffee and a bacon egg & cheese on a croissant.

$7.89
Nothing Bundt Cakes

Bundtlet Duo

Two personal-sized bundtlets in your choice of classic flavors.

$12.50

File Structure

├── src
`  `├── App.tsx `← we are here`
`  `├── index.css
`  `└── main.tsx

Distraction free code

const [cards, setCards] = useState([
  { icon: Coffee, header: 'Starbucks', title: "A 'Giftzy Latte'", ... },
  { icon: IceCreamCone, header: 'Cold Stone', title: "Berry Good Combo", ... },
  ...
]);
{/*Grid*/}
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4'>
  {cards.map((card, index) => (
    <div key={index}>
      {/*Header*/}
        <card.icon />
        <span>{card.header}</span>
        <Star />
      {/*Body*/}
        <h2>{card.title}</h2>
        {card.isNew && <span>New</span>}
        <p>{card.description}</p>
      {/*Footer*/}
        <span>{card.price}</span>
        <button><Info /></button>
        <button>Details</button>
    </div>
  ))}
</div>

Code

'use client';

import { Coffee, Star, Info, IceCreamCone, Cake, Cookie } from 'lucide-react';
import { useState } from 'react';

export default function Home() {
  const [cards, setCards] = useState([
    {
      icon: Coffee,
      header: 'Starbucks',
      title: "A 'Giftzy Latte'",
      description: 'One venti Caffe Latte and one Double Chocolate Brownie from Starbucks.',
      price: '$11.07',
      isNew: true,
    },
    {
      icon: IceCreamCone,
      header: 'Cold Stone',
      title: 'Berry Good Combo',
      description: 'A medium Berry Berry Berry Good ice cream with waffle cone and topping.',
      price: '$8.49',
      isNew: false,
    },
    {
      icon: Cake,
      header: 'The Cheesecake Factory',
      title: 'Slice of Heaven',
      description: 'One slice of Original Cheesecake with a fresh strawberry topping.',
      price: '$9.95',
      isNew: true,
    },
    {
      icon: Cookie,
      header: 'Crumbl',
      title: 'Cookie Party Box',
      description: 'A four-pack of weekly rotating flavors from Crumbl Cookies.',
      price: '$15.99',
      isNew: false,
    },
    {
      icon: Coffee,
      header: "Dunkin'",
      title: 'Morning Kickstart',
      description: 'A medium iced coffee and a bacon egg & cheese on a croissant.',
      price: '$7.89',
      isNew: true,
    },
    {
      icon: Cake,
      header: 'Nothing Bundt Cakes',
      title: 'Bundtlet Duo',
      description: 'Two personal-sized bundtlets in your choice of classic flavors.',
      price: '$12.50',
      isNew: false,
    },
  ]);

  return (
    <div className='py-4 bg-gray-200 min-h-screen p-4'>
      <div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 max-w-5xl mx-auto'>
        {cards.map((card, index) => (
          <div key={index} className='bg-white rounded-2xl shadow-md w-full overflow-hidden'>
            {/* Header */}
            <div className='flex items-center justify-between px-5 pt-5 pb-4'>
              <div className='flex items-center gap-3'>
                <div className='w-10 h-10 bg-green-700 rounded-full flex items-center justify-center'>
                  <card.icon className='w-5 h-5 text-white' />
                </div>
                <span className='text-base font-semibold text-gray-900'>{card.header}</span>
              </div>
              <button className='text-gray-300 hover:text-yellow-400 transition-colors'>
                <Star className='w-5 h-5' />
              </button>
            </div>

            {/* Divider */}
            <div className='border-t border-gray-100 mx-5' />

            {/* Body */}
            <div className='px-5'>
              <div className='flex items-center'>
                <h2 className='text-lg font-semibold text-gray-900 pt-4'>{card.title}</h2>
                {card.isNew && (
                  <span className='text-xs font-medium text-green-600 bg-green-50 px-2 py-0.5 rounded-full'>New</span>
                )}
              </div>
              <p className='text-sm text-gray-500 leading-relaxed pb-2'>{card.description}</p>
            </div>

            {/* Footer */}
            <div className='flex items-center justify-between px-5 pt-3 pb-5'>
              <div className='flex items-center gap-1.5'>
                <span className='text-xl font-bold text-gray-900'>{card.price}</span>
                <button className='text-gray-300 hover:text-gray-500 transition-colors'>
                  <Info className='w-4 h-4' />
                </button>
              </div>
              <button className='text-sm font-medium text-teal-600 border border-teal-600 rounded-full px-5 py-1.5 hover:bg-teal-50 transition-colors'>
                Details
              </button>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Layer Visualisation

Layers

Approximation of how this code would look in Figma's layer panel.

Home
LucideImport
ReactImport
cards"[{ icon, header, title, description, price, isNew }, ...]"
cardsData"[{ icon: Coffee, header: 'Starbucks', isNew: true }, ...]"
PageWrapper
CardGrid
GiftCard
CardHeader
BrandGroup
BrandIconWrapper
CardIcon
BrandName"{card.header}"
FavoriteButton
StarIcon
Divider
CardBody
TitleRow
CardTitle"{card.title}"
ShowNewBadgeIfNew
NewBadge"New"
CardDescription"{card.description}"
CardFooter
PriceGroup
PriceLabel"{card.price}"
InfoButton
InfoIcon
DetailsButton"Details"
Select a layer to inspect

What's new and what's happening?

Yay!

No new concepts — this builds on array + .map() from the previous lesson and reuses the same card template.

On this page