HTML Tutorial
HTML Project: Product Card
A product card with a name, price, feature list, and a call-to-action button.
What you will build
A product card for the Cedar Desk Lamp. The card shows the name, a price, four features, an order button, and a line of small print. CSS frames it like a shop tile. HTML still names every part.
The button does not charge a card. It is a control in the page, often a link styled as a button, or abutton inside a form. This project uses a form with method="post" so the order action is explicit even without a backend.
Use Try it in HTML to open /html/try. You want the card to look finished in that preview, not in a Python editor.
Tags you will use
| Tag | Job on this page |
|---|---|
article | The product as a self-contained card |
h1 | Product name |
p | Price and small print |
ul | Four features |
form and button | The order action |
Price belongs in text you can copy. Do not hide it only in an image of a tag.
Build in slices
Name and price first. Put the amount in a data element if you want a machine-readable value. A plain paragraph is still honest.
Example
<article class="product">
<h1>Cedar Desk Lamp</h1>
<p class="price"><data value="89.00">89.00 EUR</data></p>
</article>Add the four features and the small print. Features are a list. Small print is not a feature.
Example
<ul class="features">
<li>Solid cedar base, oiled not varnished</li>
<li>Linen shade, warm 2700 K bulb included</li>
<li>Brass stem with a simple dimmer</li>
<li>Cable long enough for a deep desk</li>
</ul>
<p class="fine">Made to order. Ships in 12 days. Returns within 14 days if unused.</p>Keep the order control in the card. A button that lives in a sticky bar elsewhere is a different page. This project is one tile. Preview that tile at /html/try.
Complete document
A placeholder block stands in for a photo. It is a colored panel with a caption, not a remote image. The form posts nowhere useful, which is correct for this tutorial.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cedar Desk Lamp</title>
<style>
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: #ece7de;
font-family: "Segoe UI", sans-serif;
color: #1c1917;
}
.product {
width: min(22rem, 92vw);
background: #fffaf3;
border: 1px solid #c4b8a5;
padding: 0 0 1.1rem;
}
.photo {
height: 10rem;
background: linear-gradient(#d7c4a3, #8d6b45);
display: grid;
place-items: center;
color: #fffaf3;
letter-spacing: 0.12em;
text-transform: uppercase;
font-size: 0.75rem;
}
h1, .price, .features, form, .fine { margin-left: 1rem; margin-right: 1rem; }
h1 { font-size: 1.35rem; margin-bottom: 0.2rem; }
.price { font-size: 1.2rem; color: #7c2d12; }
.features { padding-left: 1.1rem; }
button {
background: #1f4d3a;
color: #fff;
border: 0;
padding: 0.55rem 1rem;
font: inherit;
width: calc(100% - 2rem);
cursor: pointer;
}
.fine { font-size: 0.8rem; color: #57534e; }
</style>
</head>
<body>
<article class="product">
<div class="photo" role="img" aria-label="Cedar lamp on a clear desk">Studio sketch</div>
<h1>Cedar Desk Lamp</h1>
<p class="price"><data value="89.00">89.00 EUR</data></p>
<ul class="features">
<li>Solid cedar base, oiled not varnished</li>
<li>Linen shade, warm 2700 K bulb included</li>
<li>Brass stem with a simple dimmer</li>
<li>Cable long enough for a deep desk</li>
</ul>
<form action="#" method="post">
<button type="submit">Order lamp</button>
</form>
<p class="fine">Made to order. Ships in 12 days. Returns within 14 days if unused.</p>
</article>
</body>
</html>A second complete card
Same parts: name, price, four features, order button, small print. New product, new colors.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Field satchel</title>
<style>
body { margin: 0; background: #111827; color: #f3f4f6; font-family: Georgia, serif; display: grid; place-items: center; min-height: 100vh; }
.product { width: min(22rem, 92vw); background: #1f2937; padding: 1rem 1.1rem 1.2rem; border-top: 8px solid #f59e0b; }
.price { color: #fbbf24; font-size: 1.25rem; }
button { background: #f59e0b; border: 0; padding: 0.5rem 0.9rem; font: inherit; width: 100%; }
.fine { font-size: 0.8rem; color: #9ca3af; }
</style>
</head>
<body>
<article class="product">
<h1>Field satchel</h1>
<p class="price"><data value="64.00">64.00 EUR</data></p>
<ul>
<li>Waxed canvas, repairable seams</li>
<li>One main pocket, one pen sleeve</li>
<li>Strap long enough for a coat</li>
<li>Brass buckle, not a plastic clip</li>
</ul>
<form action="#" method="post">
<button type="submit">Order satchel</button>
</form>
<p class="fine">Cut in batches of twenty. Dye lots vary. No rush shipping.</p>
</article>
</body>
</html>Common mistakes
- A button that is only a
divwith a click style. Usebuttonor a real link. - Features written as one paragraph with commas. Four lines scan. A blob does not.
- Small print in a tiny pale gray that fails contrast. Quiet is not invisible.
- Price with no currency. “89” is not an offer.
- A product photo from a CDN. Use a colored block or SVG so the card still renders.
Practice tasks
- Change the lamp into a product you own. Keep four features and a price with a currency.
- Add a second sentence of small print about warranty. Keep it in the same
p.fine. - Restyle the button hover with CSS. Confirm the default still looks like a button at /html/try.