List Products Grid Block
The ListProductsGrid Component is a fully customizable and accessible grid layout for displaying products built with React and TypeScript. It provides a complete product listing interface with modern design patterns, flexible customization options, and composable sub-components for titles, items, and cards.
π Installationβ
npm install @nodeblocks/frontend-list-products-grid-block
π Usageβ
import {ListProductsGrid} from '@nodeblocks/frontend-list-products-grid-block';
- Basic Usage
- Advanced Usage
function ProductsGridExample() { const data: ComponentProps<typeof ListProductsGrid.Items.GridCard>[] = [ { chips: [{ label: 'New' }], tags: [{ icon: 'shopping_bag', label: 'Category 1' }], subtitleImageUrl: '', summary: 'This is a summary of something', imageUrl: 'https://unsplash.it/640?random&x=' + Math.random(), subtitle: 'Product Card subtitle 1', title: 'Product Card Title 1', linkProps: { href: '/products/1', onNavigate: () => console.log('Navigating to product 1') } }, { chips: [{ label: 'New' }], tags: [{ icon: 'shopping_bag', label: 'Category 1' }], linkProps: { href: '/my/product/card2', onNavigate: () => {} }, imageUrl: 'https://unsplash.it/640?random&x=' + Math.random(), subtitle: 'Product Card subtitle 2', title: 'Product Card Title 2', }, { chips: [{ label: 'New' }], tags: [{ icon: 'shopping_bag', label: ['Category 1', 'Category 2'] }], linkProps: { href: '/my/product/card3', onNavigate: () => {} }, imageUrl: 'https://unsplash.it/640?random&x=' + Math.random(), subtitle: 'Product Card subtitle 3', title: 'Product Card Title 3', }, ]; return ( <ListProductsGrid listProductsGridTitle="Our Products" subtitle="Featured Items" className="custom-grid"> <ListProductsGrid.Title /> <ListProductsGrid.Items> {data.map((props, i) => ( <ListProductsGrid.Items.GridCard key={i} {...props} /> ))} </ListProductsGrid.Items> </ListProductsGrid> ); }
function CustomProductsGrid() { const categories = [ { name: 'Electronics', icon: 'π»', products: [ { title: 'Gaming Laptop', price: '$1,299', rating: 4.8, image: 'https://unsplash.it/300?random&electronics=1', badge: 'Best Seller' }, { title: 'Wireless Headphones', price: '$299', rating: 4.6, image: 'https://unsplash.it/300?random&electronics=2', badge: 'New' } ] }, { name: 'Fashion', icon: 'π', products: [ { title: 'Designer Jacket', price: '$199', rating: 4.9, image: 'https://unsplash.it/300?random&fashion=1', badge: 'Trending' }, { title: 'Premium Sneakers', price: '$149', rating: 4.7, image: 'https://unsplash.it/300?random&fashion=2', badge: 'Limited' } ] } ]; return ( <ListProductsGrid listProductsGridTitle="Product Categories" subtitle="Shop by Category" className="category-grid"> {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { title: defaultBlocks.title, // Complete override of items section with category-based layout items: ( <div style={{ display: 'grid', gap: '32px' }}> {categories.map((category, categoryIndex) => ( <div key={categoryIndex} style={{ background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)', borderRadius: '20px', padding: '32px', color: 'white' }}> <div style={{ display: 'flex', alignItems: 'center', marginBottom: '24px', gap: '16px' }}> <span style={{ fontSize: '32px' }}>{category.icon}</span> <h2 style={{ fontSize: '28px', fontWeight: 'bold', margin: 0 }}> {category.name} </h2> </div> <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: '20px' }}> {category.products.map((product, productIndex) => ( <div key={productIndex} style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '16px', padding: '20px', backdropFilter: 'blur(10px)', border: '1px solid rgba(255,255,255,0.2)', transition: 'all 0.3s ease', cursor: 'pointer' }} onMouseOver={(e) => { e.currentTarget.style.transform = 'translateY(-8px)'; e.currentTarget.style.boxShadow = '0 20px 40px rgba(0,0,0,0.2)'; }} onMouseOut={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; }}> <div style={{ position: 'relative', marginBottom: '16px', borderRadius: '12px', overflow: 'hidden', height: '200px' }}> <img src={product.image} alt={product.title} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> <div style={{ position: 'absolute', top: '12px', right: '12px', background: 'rgba(255,255,255,0.9)', color: '#333', padding: '6px 12px', borderRadius: '20px', fontSize: '12px', fontWeight: '600' }}> {product.badge} </div> </div> <h3 style={{ fontSize: '18px', fontWeight: '600', marginBottom: '8px', margin: '0 0 8px 0' }}> {product.title} </h3> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}> <span style={{ fontSize: '20px', fontWeight: 'bold', color: '#fff' }}> {product.price} </span> <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}> <span>β</span> <span style={{ fontSize: '14px' }}> {product.rating} </span> </div> </div> <button style={{ width: '100%', background: 'rgba(255,255,255,0.2)', border: '1px solid rgba(255,255,255,0.3)', borderRadius: '8px', padding: '12px', color: 'white', fontSize: '14px', fontWeight: '600', cursor: 'pointer', transition: 'all 0.3s ease' }} onMouseOver={(e) => { e.target.style.background = 'rgba(255,255,255,0.3)'; }} onMouseOut={(e) => { e.target.style.background = 'rgba(255,255,255,0.2)'; }}> Add to Cart </button> </div> ))} </div> <div style={{ textAlign: 'center', marginTop: '24px' }}> <button style={{ background: 'rgba(255,255,255,0.2)', border: '2px solid rgba(255,255,255,0.3)', borderRadius: '25px', padding: '12px 32px', color: 'white', fontSize: '16px', fontWeight: '600', cursor: 'pointer', backdropFilter: 'blur(10px)', transition: 'all 0.3s ease' }} onMouseOver={(e) => { e.target.style.background = 'rgba(255,255,255,0.3)'; e.target.style.transform = 'translateY(-2px)'; }} onMouseOut={(e) => { e.target.style.background = 'rgba(255,255,255,0.2)'; e.target.style.transform = 'translateY(0)'; }}> View All {category.name} β </button> </div> </div> ))} </div> ) }, blockOrder: ['title', 'items'] })} </ListProductsGrid> ); }
π§ Props Referenceβ
Main Component Propsβ
The main ListProductsGrid
component inherits all props from the HTML div
element (except children
which is overridden) and adds:
Prop | Type | Default | Description |
---|---|---|---|
listProductsGridTitle | ReactNode | undefined | Main title for the product list |
subtitle | string | undefined | Secondary title displayed above the main title |
className | string | undefined | Additional CSS class name for styling the grid container |
children | BlocksOverride | undefined | Custom block components to override default rendering |
Sub-Componentsβ
The ListProductsGrid component provides several sub-components. All sub-components receive their default values from the main component's context and can override these values through props.
ListProductsGrid.Titleβ
Prop | Type | Default | Description |
---|---|---|---|
listProductsGridTitle | ReactNode | From context | Content to display as the main title |
subtitle | string | From context | Content to display as the subtitle |
direction | enum | "column" | Flex direction for action buttons |
alignItems | enum | "stretch" | Alignment of items in the container |
gapSize | enum | "S" | Gap between items in the container |
children | ReactNode | Default title layout | Custom content to override the default title layout |
className | string | undefined | Additional CSS class name for styling the title container |
ListProductsGrid.Itemsβ
Prop | Type | Default | Description |
---|---|---|---|
direction | enum | "column" | Flex direction for action buttons |
alignItems | enum | "stretch" | Alignment of items in the container |
gapSize | enum | "S" | Gap between items in the container |
children | ReactNode | Default title layout | Custom content to override the default items card layout |
className | string | undefined | Additional CSS class name for styling the items container |
ListProductsGrid.Items.GridCardβ
Prop | Type | Default | Description |
---|---|---|---|
title | string | undefined | Main title displayed on the card |
subtitle | string | undefined | Secondary text displayed below the title |
summary | string | undefined | Brief description or summary text |
imageUrl | string | undefined | URL of the main image displayed on the card |
subtitleImageUrl | string | undefined | URL of a small image displayed next to the subtitle |
chips | Array<{label: string}> | undefined | Array of chip objects to display as badges |
tags | Array<{icon: enum, label: string | string[]}> | undefined | Array of tag objects with icons and labels |
linkProps | {href: string, onNavigate: () => void} | undefined | Navigation properties for making the card clickable |
className | string | undefined | Additional CSS class name for styling the card |
children | ReactNode | undefined | Custom content to display inside the card (overrides default layout) |
π§ TypeScript Supportβ
Full TypeScript support with comprehensive type definitions:
import {ListProductsGrid} from '@nodeblocks/frontend-list-products-grid-block';
import {ComponentProps} from 'react';
// Default grid card data structure
interface DefaultGridCardData {
title?: string;
subtitle?: string;
summary?: string;
imageUrl?: string;
subtitleImageUrl?: string;
chips?: Array<{label: string}>;
tags?: Array<{icon: string, label: string | string[]}>;
linkProps?: {href: string, onNavigate: () => void};
}
// Extend with custom fields
interface CustomGridCardData extends DefaultGridCardData {
category?: string;
price?: number;
rating?: number;
customField?: string;
}
const MyProductsGrid = () => {
const products: ComponentProps<typeof ListProductsGrid.Items.GridCard>[] = [
{
title: 'Product 1',
subtitle: 'Premium Quality',
summary: 'This is a detailed description of product 1',
imageUrl: 'https://example.com/product1.jpg',
chips: [{ label: 'New' }, { label: 'Featured' }],
tags: [
{ icon: 'shopping_bag', label: 'Electronics' },
{ icon: 'star', label: ['Best Seller', 'Top Rated'] }
],
linkProps: {
href: '/products/1',
onNavigate: () => console.log('Navigating to product 1')
}
},
// ... more products
];
return (
<ListProductsGrid
listProductsGridTitle="Our Products"
subtitle="Featured Collection"
className="custom-grid">
<ListProductsGrid.Title />
<ListProductsGrid.Items>
{products.map((props, index) => (
<ListProductsGrid.Items.GridCard key={index} {...props} />
))}
</ListProductsGrid.Items>
</ListProductsGrid>
);
};
Built with β€οΈ using React, TypeScript, and modern web standards.