Product Card
POS product cards with image, badges, price, stock indicator, quick-add button, and responsive grid layout.
Basic Product Card
Preview
Café Espresso
€2.50
En stock
<div style="max-width: 200px;">
<div class="product-card">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
<button class="product-card-quick-add">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>
</button>
</div>
<div class="product-card-content">
<p class="product-card-name">Café Espresso</p>
<div class="product-card-price-wrapper">
<span class="product-card-price">€2.50</span>
</div>
<span class="product-card-stock product-card-stock-available">En stock</span>
</div>
</div>
</div> Requires: ux.min.css
<div style="max-width: 200px;">
<div class="flex flex-col overflow-hidden cursor-pointer select-none bg-base-100 border border-base-300 rounded-box hover:border-primary hover:shadow-lg transition-all">
<div class="relative overflow-hidden aspect-square bg-base-200">
<div class="flex items-center justify-center w-full h-full bg-gradient-to-br from-base-200 to-base-300 text-base-content/40">
<svg class="w-12 h-12 opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
<button class="absolute bottom-2 right-2 flex items-center justify-center w-9 h-9 bg-primary text-primary-content border-none rounded-full opacity-0 scale-80 hover:brightness-90 transition-all z-3">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>
</button>
</div>
<div class="flex flex-col flex-1 gap-1 p-2">
<p class="text-sm font-medium m-0 overflow-hidden line-clamp-2">Café Espresso</p>
<span class="text-lg font-bold tabular-nums">€2.50</span>
<span class="text-xs text-success">En stock</span>
</div>
</div>
</div> Requires: tw.min.css
// Quick-add button
document.querySelectorAll('.product-card-quick-add').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const card = btn.closest('.product-card');
card.classList.add('product-card-adding');
setTimeout(() => card.classList.remove('product-card-adding'), 500);
// Add to cart logic...
});
}); With Badges & Sale Price
Preview
-20%
Nuevo
Bebidas
Zumo de Naranja Natural
€3.20
€4.00
-20%
Quedan 3
<div style="max-width: 200px;">
<div class="product-card">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
<div class="product-card-badges">
<span class="product-card-badge product-card-badge-sale">-20%</span>
<span class="product-card-badge product-card-badge-new">Nuevo</span>
</div>
<button class="product-card-quick-add">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>
</button>
</div>
<div class="product-card-content">
<span class="product-card-category">Bebidas</span>
<p class="product-card-name">Zumo de Naranja Natural</p>
<div class="product-card-price-wrapper">
<span class="product-card-price product-card-price-sale">€3.20</span>
<span class="product-card-price-original">€4.00</span>
<span class="product-card-discount">-20%</span>
</div>
<span class="product-card-stock product-card-stock-low">Quedan 3</span>
</div>
</div>
</div> Requires: ux.min.css
<div style="max-width: 200px;">
<div class="flex flex-col overflow-hidden cursor-pointer select-none bg-base-100 border border-base-300 rounded-box hover:border-primary hover:shadow-lg transition-all">
<div class="relative overflow-hidden aspect-square bg-base-200">
<div class="flex items-center justify-center w-full h-full bg-gradient-to-br from-base-200 to-base-300 text-base-content/40">
<svg class="w-12 h-12 opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
<div class="absolute flex flex-wrap gap-1 top-1 left-1 right-1 z-2">
<span class="inline-flex items-center text-xs font-semibold uppercase px-1 py-0.5 bg-error text-white rounded-field tracking-wide">-20%</span>
<span class="inline-flex items-center text-xs font-semibold uppercase px-1 py-0.5 bg-success text-white rounded-field tracking-wide">Nuevo</span>
</div>
</div>
<div class="flex flex-col flex-1 gap-1 p-2">
<span class="text-xs uppercase text-base-content/40 tracking-wide">Bebidas</span>
<p class="text-sm font-medium m-0 overflow-hidden line-clamp-2">Zumo de Naranja Natural</p>
<div class="flex items-baseline gap-1 flex-wrap">
<span class="text-lg font-bold text-error tabular-nums">€3.20</span>
<span class="text-sm line-through text-base-content/40">€4.00</span>
<span class="text-xs font-semibold text-error bg-error/10 px-1 py-0.5 rounded-field">-20%</span>
</div>
<span class="text-xs text-warning">Quedan 3</span>
</div>
</div>
</div> Requires: tw.min.css
// No additional JS needed for badges/pricing — CSS only Product Grid
Preview
Café Espresso
€2.50Tostada Integral
€1.80Zumo Natural
€3.50
Agotado
Croissant
€1.50 Sin stock<div class="product-grid product-grid-4">
<div class="product-card">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
</div>
<div class="product-card-content">
<p class="product-card-name">Café Espresso</p>
<span class="product-card-price">€2.50</span>
</div>
</div>
<div class="product-card">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
</div>
<div class="product-card-content">
<p class="product-card-name">Tostada Integral</p>
<span class="product-card-price">€1.80</span>
</div>
</div>
<div class="product-card">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
</div>
<div class="product-card-content">
<p class="product-card-name">Zumo Natural</p>
<span class="product-card-price">€3.50</span>
</div>
</div>
<div class="product-card product-card-out-of-stock">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
<div class="product-card-badges">
<span class="product-card-badge product-card-badge-out">Agotado</span>
</div>
</div>
<div class="product-card-content">
<p class="product-card-name">Croissant</p>
<span class="product-card-price">€1.50</span>
<span class="product-card-stock product-card-stock-out">Sin stock</span>
</div>
</div>
</div> Requires: ux.min.css
<div class="grid grid-cols-4 gap-4">
<!-- Repeat product cards using Tailwind classes from above examples -->
<!-- .product-grid-4 sets 4 columns, responsive to 3 on tablet and 2 on mobile -->
</div> Requires: tw.min.css
// No JS needed for grid layout — CSS handles responsive columns Horizontal & Sizes
Preview
Comida
Ensalada César con pollo
SKU: ERPl-0042
€8.90
Agua 0.5L
€1.00<!-- Horizontal layout -->
<div class="product-card product-card-horizontal" style="max-width: 360px;">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
</div>
</div>
<div class="product-card-content">
<span class="product-card-category">Comida</span>
<p class="product-card-name">Ensalada César con pollo</p>
<span class="product-card-sku">SKU: ERPl-0042</span>
<div class="product-card-price-wrapper">
<span class="product-card-price">€8.90</span>
</div>
</div>
</div>
<!-- Small -->
<div style="max-width: 140px; margin-top: 1rem;">
<div class="product-card product-card-sm">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>
</div>
</div>
<div class="product-card-content">
<p class="product-card-name">Agua 0.5L</p>
<span class="product-card-price">€1.00</span>
</div>
</div>
</div> Requires: ux.min.css
<!-- Horizontal: add flex-row to the card, image wrapper gets fixed width -->
<!-- Small: smaller padding, text-xs name, text-base price --> Requires: tw.min.css
// No JS needed — layout is CSS only Selected & Glass
Preview
Café Latte
€3.00Té Verde
€2.20<div class="flex gap-4 flex-wrap">
<!-- Selected state -->
<div style="max-width: 180px;">
<div class="product-card product-card-selected">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>
</div>
</div>
<div class="product-card-content">
<p class="product-card-name">Café Latte</p>
<span class="product-card-price">€3.00</span>
</div>
</div>
</div>
<!-- Glass -->
<div style="max-width: 180px; background: linear-gradient(135deg, #667eea, #764ba2); padding: 1rem; border-radius: 0.75rem;">
<div class="product-card glass">
<div class="product-card-image-wrapper">
<div class="product-card-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>
</div>
</div>
<div class="product-card-content">
<p class="product-card-name">Té Verde</p>
<span class="product-card-price">€2.20</span>
</div>
</div>
</div>
</div> Requires: ux.min.css
<!-- Selected: border-primary + ring shadow -->
<!-- Glass: add .glass class for glass morphism --> Requires: tw.min.css
// Toggle selected state
document.querySelectorAll('.product-card').forEach(card => {
card.addEventListener('click', () => {
document.querySelectorAll('.product-card').forEach(c => c.classList.remove('product-card-selected'));
card.classList.add('product-card-selected');
});
});