📦 Product Components
Product cards, listings, galleries, and detailed product display components
🎭 Component Demonstrations
Interactive product components including cards, galleries, ratings, and inventory indicators
Product Cards
Various product card layouts for different display contexts
Wireless Headphones
High-quality wireless headphones with noise cancellation
Bluetooth Speaker
Featured Product
Premium Smartphone Case
Product Swatches
Color, size, and material selection components
T-Shirt Options
Color
Selected:
Size
Selected:
Material
Your Selection:
T-Shirt, Size , Material
Product Image Gallery
Interactive image galleries with zoom and navigation
Product Images
Product Ratings
Rating displays and review components for customer feedback
Customer Reviews
Recent Reviews
Stock Status Indicators
Visual indicators for product availability and inventory levels
Wireless Mouse
✅USB Drive
⚠️Gaming Keyboard
❌📝 Usage Examples
Code snippets for implementing product components in your Hyvä theme
Basic Product Card with Alpine.js
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow"
x-data="{ isWishlisted: false }">
<div class="relative">
<img src="<?= $escaper->escapeUrl($product->getImageUrl()) ?>"
alt="<?= $escaper->escapeHtmlAttr($product->getName()) ?>"
class="w-full h-48 object-cover loading-lazy">
<button @click="isWishlisted = !isWishlisted"
class="absolute top-2 right-2 p-2 bg-white rounded-full shadow-md hover:bg-red-50"
:class="isWishlisted ? 'text-red-500' : 'text-gray-400'">
<span x-text="isWishlisted ? '♥' : '♡'"></span>
</button>
</div>
<div class="p-4">
<h3 class="font-semibold text-gray-900 mb-2"><?= $escaper->escapeHtml($product->getName()) ?></h3>
<div class="flex items-center justify-between">
<span class="text-fluid-xl font-bold text-gray-900">$<?= $escaper->escapeHtml($product->getPrice()) ?></span>
<button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors">
Add to Cart
</button>
</div>
</div>
</div>
Product Quick Actions (Wishlist, Compare)
<div class="flex space-x-2" x-data="{
wishlist: [],
compare: [],
addToWishlist(productId) {
if (!this.wishlist.includes(productId)) {
this.wishlist.push(productId);
}
},
addToCompare(productId) {
if (!this.compare.includes(productId) && this.compare.length < 3) {
this.compare.push(productId);
}
}
}">
<button @click="addToWishlist(<?= $product->getId() ?>)"
:class="wishlist.includes(<?= $product->getId() ?>) ? 'text-red-500' : 'text-gray-400'"
class="p-2 hover:bg-gray-100 rounded transition-colors"
title="Add to Wishlist">
♡
</button>
<button @click="addToCompare(<?= $product->getId() ?>)"
:class="compare.includes(<?= $product->getId() ?>) ? 'text-blue-500' : 'text-gray-400'"
class="p-2 hover:bg-gray-100 rounded transition-colors"
title="Add to Compare">
⚖️
</button>
<span x-show="compare.length > 0"
class="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded">
Compare (<span x-text="compare.length"></span>)
</span>
</div>
Product Rating and Review Integration
<div class="space-y-3" x-data="{
rating: <?= $product->getRatingSummary() ?>,
reviewCount: <?= $product->getReviewsCount() ?>,
showReviews: false
}">
<!-- Star Rating Display -->
<div class="flex items-center space-x-2">
<div class="flex text-yellow-400">
<template x-for="star in 5" :key="star">
<span x-text="star <= Math.floor(rating/20) ? '★' : '☆'"></span>
</template>
</div>
<span class="text-sm text-gray-600" x-text="`(${reviewCount} reviews)`"></span>
</div>
<!-- Reviews Toggle -->
<button @click="showReviews = !showReviews"
class="text-blue-600 hover:text-blue-800 text-sm underline">
<span x-text="showReviews ? 'Hide Reviews' : 'Show Reviews'"></span>
</button>
<!-- Reviews Section -->
<div x-show="showReviews" x-transition class="border-t pt-3">
<div class="space-y-2">
<?php foreach ($block->getReviews() as $review): ?>
<div class="p-3 bg-gray-50 rounded">
<div class="flex items-center justify-between mb-1">
<div class="flex text-yellow-400 text-xs">
<?= str_repeat('★', $review->getRating()) ?>
<?= str_repeat('☆', 5 - $review->getRating()) ?>
</div>
<span class="text-xs text-gray-500"><?= $review->getCreatedAt() ?></span>
</div>
<p class="text-sm text-gray-700"><?= $escaper->escapeHtml($review->getDetail()) ?></p>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
⚡ Performance & Accessibility
Best practices for optimized and accessible product components
Product Accessibility
Implement proper image alt text, price formatting with currency symbols, ARIA labels for interactive elements, and keyboard navigation support for all product actions.
Performance Optimization
Enable image lazy loading with loading="lazy", use efficient Alpine.js data binding, implement virtual scrolling for large product lists, and optimize image formats (AVIF with JPEG fallback).
Mobile-Friendly Interactions
Design touch-friendly buttons (minimum 44px target size), implement swipe gestures for image galleries, optimize for thumb navigation, and ensure readable text at mobile viewport sizes.
SEO Considerations
Add structured data markup (Product schema), implement semantic HTML5 elements, optimize meta descriptions and titles, and ensure proper heading hierarchy for search engine crawling.