ecommerce / components / product-overviews
Split With Image And Featured Details
03-split-with-image-and-featured-details.jsx
import { CheckCircleIcon, CheckIcon, QuestionMarkCircleIcon, StarIcon } from '@heroicons/react/20/solid'
import { ShieldCheckIcon } from '@heroicons/react/24/outline'
const product = {
name: 'Everyday Ruck Snack',
href: '#',
price: '$220',
description:
"Don't compromise on snack-carrying capacity with this lightweight and spacious bag. The drawstring top keeps all your favorite chips, crisps, fries, biscuits, crackers, and cookies secure.",
imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-04-featured-product-shot.jpg',
imageAlt: 'Model wearing light green backpack with black canvas straps and front zipper pouch.',
breadcrumbs: [
{ id: 1, name: 'Travel', href: '#' },
{ id: 2, name: 'Bags', href: '#' },
],
sizes: [
{ name: '18L', description: 'Perfect for a reasonable amount of snacks.' },
{ name: '20L', description: 'Enough room for a large amount of snacks.' },
],
}
const reviews = { average: 4, totalCount: 1624 }
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function Example() {
return (
<div className="bg-white">
<div className="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:grid lg:max-w-7xl lg:grid-cols-2 lg:gap-x-8 lg:px-8">
{/* Product details */}
<div className="lg:max-w-lg lg:self-end">
<nav aria-label="Breadcrumb">
<ol role="list" className="flex items-center space-x-2">
{product.breadcrumbs.map((breadcrumb, breadcrumbIdx) => (
<li key={breadcrumb.id}>
<div className="flex items-center text-sm">
<a href={breadcrumb.href} className="font-medium text-gray-500 hover:text-gray-900">
{breadcrumb.name}
</a>
{breadcrumbIdx !== product.breadcrumbs.length - 1 ? (
<svg
fill="currentColor"
viewBox="0 0 20 20"
aria-hidden="true"
className="ml-2 size-5 shrink-0 text-gray-300"
>
<path d="M5.555 17.776l8-16 .894.448-8 16-.894-.448z" />
</svg>
) : null}
</div>
</li>
))}
</ol>
</nav>
<div className="mt-4">
<h1 className="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">{product.name}</h1>
</div>
<section aria-labelledby="information-heading" className="mt-4">
<h2 id="information-heading" className="sr-only">
Product information
</h2>
<div className="flex items-center">
<p className="text-lg text-gray-900 sm:text-xl">{product.price}</p>
<div className="ml-4 border-l border-gray-300 pl-4">
<h2 className="sr-only">Reviews</h2>
<div className="flex items-center">
<div>
<div className="flex items-center">
{[0, 1, 2, 3, 4].map((rating) => (
<StarIcon
key={rating}
aria-hidden="true"
className={classNames(
reviews.average > rating ? 'text-yellow-400' : 'text-gray-300',
'size-5 shrink-0',
)}
/>
))}
</div>
<p className="sr-only">{reviews.average} out of 5 stars</p>
</div>
<p className="ml-2 text-sm text-gray-500">{reviews.totalCount} reviews</p>
</div>
</div>
</div>
<div className="mt-4 space-y-6">
<p className="text-base text-gray-500">{product.description}</p>
</div>
<div className="mt-6 flex items-center">
<CheckIcon aria-hidden="true" className="size-5 shrink-0 text-green-500" />
<p className="ml-2 text-sm text-gray-500">In stock and ready to ship</p>
</div>
</section>
</div>
{/* Product image */}
<div className="mt-10 lg:col-start-2 lg:row-span-2 lg:mt-0 lg:self-center">
<img alt={product.imageAlt} src={product.imageSrc} className="aspect-square w-full rounded-lg object-cover" />
</div>
{/* Product form */}
<div className="mt-10 lg:col-start-1 lg:row-start-2 lg:max-w-lg lg:self-start">
<section aria-labelledby="options-heading">
<h2 id="options-heading" className="sr-only">
Product options
</h2>
<form>
<div className="sm:flex sm:justify-between">
{/* Size selector */}
<fieldset>
<legend className="block text-sm font-medium text-gray-700">Size</legend>
<div className="mt-1 grid grid-cols-1 gap-4 sm:grid-cols-2">
{product.sizes.map((size) => (
<label
key={size.name}
aria-label={size.name}
aria-description={size.description}
className="group relative flex rounded-lg border border-gray-300 bg-white p-4 has-checked:outline-2 has-checked:-outline-offset-2 has-checked:outline-indigo-600 has-focus-visible:outline-3 has-focus-visible:-outline-offset-1 has-disabled:border-gray-400 has-disabled:bg-gray-200 has-disabled:opacity-25"
>
<input
defaultValue={size.name}
defaultChecked={size === product.sizes[0]}
name="size"
type="radio"
className="absolute inset-0 appearance-none focus:outline-none"
/>
<div className="flex-1">
<span className="block text-base font-medium text-gray-900">{size.name}</span>
<span className="mt-1 block text-sm text-gray-500">{size.description}</span>
</div>
<CheckCircleIcon
aria-hidden="true"
className="invisible size-5 text-indigo-600 group-has-checked:visible"
/>
</label>
))}
</div>
</fieldset>
</div>
<div className="mt-4">
<a href="#" className="group inline-flex text-sm text-gray-500 hover:text-gray-700">
<span>What size should I buy?</span>
<QuestionMarkCircleIcon
aria-hidden="true"
className="ml-2 size-5 shrink-0 text-gray-400 group-hover:text-gray-500"
/>
</a>
</div>
<div className="mt-10">
<button
type="submit"
className="flex w-full items-center justify-center rounded-md border border-transparent bg-indigo-600 px-8 py-3 text-base font-medium text-white hover:bg-indigo-700 focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-50 focus:outline-hidden"
>
Add to bag
</button>
</div>
<div className="mt-6 text-center">
<a href="#" className="group inline-flex text-base font-medium">
<ShieldCheckIcon
aria-hidden="true"
className="mr-2 size-6 shrink-0 text-gray-400 group-hover:text-gray-500"
/>
<span className="text-gray-500 hover:text-gray-700">Lifetime Guarantee</span>
</a>
</div>
</form>
</section>
</div>
</div>
</div>
)
}