Skip to main content

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@0.2.0

πŸ“– Usage​

import {ListProductsGrid} from '@nodeblocks/frontend-list-products-grid-block';
Live Editor
function SimpleListProductsGrid() {
  const products = [
    {
      id: '1',
      title: 'Wireless Headphones',
      description: 'Premium noise-cancelling headphones',
      price: '$199.99',
      imageUrl: 'https://placehold.co/600x400',
      badges: ['New'],
    },
    {
      id: '2',
      title: 'Smart Watch',
      description: 'Fitness tracking and notifications',
      price: '$299.99',
      originalPrice: '$349.99',
      imageUrl: 'https://placehold.co/600x400',
      badges: ['Sale'],
    },
    {
      id: '3',
      title: 'Laptop Stand',
      description: 'Ergonomic aluminum stand',
      price: '$79.99',
      imageUrl: 'https://placehold.co/600x400',
    },
    {
      id: '4',
      title: 'Mechanical Keyboard',
      description: 'RGB backlit gaming keyboard',
      price: '$149.99',
      imageUrl: 'https://placehold.co/600x400',
      badges: ['Popular'],
    },
  ];

  const handleNavigate = (href) => console.log('Navigate:', href);

  return (
    <ListProductsGrid listProductsGridTitle="Featured Products" subtitle="Check out our top picks">
      <ListProductsGrid.Title />
      <ListProductsGrid.Items>
        {products.map(product => (
          <ListProductsGrid.Items.GridCard
            key={product.id}
            title={product.title}
            imageUrl={product.imageUrl}
            summary={product.description}
            chips={product.badges?.map(b => ({label: b}))}
            linkProps={{href: `/products/${product.id}`, onNavigate: handleNavigate}}
            button={{children: product.price}}
          />
        ))}
      </ListProductsGrid.Items>
    </ListProductsGrid>
  );
}
Result
Loading...

πŸ”§ Props Reference​

Main Component Props​

PropTypeDefaultDescription
listProductsGridTitleReactNodeundefinedMain title for the product list
subtitlestringundefinedSecondary title displayed above the main title
spacingnumber5Spacing between child elements
classNamestringundefinedAdditional CSS class name for styling the grid container
childrenBlocksOverrideundefinedCustom block components to override default rendering

Note: The main component extends MUI StackProps. Default styling includes px: 2 and py: 5 padding.

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​

Container for the grid title section with subtitle and main title.

PropTypeDefaultDescription
listProductsGridTitleReactNodeFrom contextContent to display as the main title
subtitlestringFrom contextContent to display as the subtitle (displayed above title)
spacingnumber0.5Spacing between subtitle and title
childrenReactNodeDefault title layoutCustom content to override the default title layout
classNamestringundefinedAdditional CSS class name for styling

Note: This component extends MUI StackProps. Default styling includes alignItems: 'center'.

ListProductsGrid.Items​

Container for the product grid cards.

PropTypeDefaultDescription
spacingnumber2Spacing between grid items
childrenReactNodeundefinedGrid card components to render
classNamestringundefinedAdditional CSS class name for styling

Note: This component extends MUI StackProps.

ListProductsGrid.Items.GridCard​

Individual product card component with rich content options.

PropTypeDefaultDescription
titlestringRequiredMain title displayed on the card
subtitlestringundefinedSecondary text displayed below the title
subtitleImageUrlstringundefinedURL of a small image displayed next to the subtitle
summarystringundefinedBrief description or summary text
imageUrlstringundefinedURL of the main image displayed on the card
tertiaryTextstringundefinedAdditional information displayed above the title
contentstringundefinedUnrestricted text content for the card
chipsChipProps[]undefinedArray of MUI Chip props with optional leftIcon, rightIcon
tagsArray<{icon?: ReactElement, label: string | string[]}>undefinedArray of tag objects with icons and labels
titleIconReactElementundefinedIcon displayed before the title
titleActionIconButtonPropsundefinedAction button displayed after the title
buttonButtonPropsundefinedMain call-to-action button for the card
statusStatusObjectundefinedStatus callout with label and optional action
linkPropsLinkPropsundefinedNavigation properties for making the card clickable
hasDividerbooleanfalseAdd divider between card content sections
disabledbooleanfalseSet card style to disabled state
classNamestringundefinedAdditional CSS class name for styling

Note: This component extends MUI CardProps.


🎨 Configuration examples​

Custom Grid Layout:

<ListProductsGrid
listProductsGridTitle="Featured Products"
subtitle="Best Sellers"
spacing={3}
sx={{ bgcolor: '#f5f5f5', borderRadius: 2 }}
>
<ListProductsGrid.Title sx={{ textAlign: 'left', alignItems: 'flex-start' }} />
<ListProductsGrid.Items
sx={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
gap: 3
}}
>
{products.map((product, i) => (
<ListProductsGrid.Items.GridCard key={i} {...product} />
))}
</ListProductsGrid.Items>
</ListProductsGrid>

Card with Status and Actions:

<ListProductsGrid.Items.GridCard
title="Premium Headphones"
subtitle="Sony Electronics"
imageUrl="/images/headphones.jpg"
chips={[{ label: 'New', color: 'primary' }]}
status={{
label: 'In Stock',
color: 'primary',
action: {
children: 'View Details',
href: '/products/123',
onNavigate: (href) => router.push(href)
}
}}
button={{
children: 'Add to Cart',
variant: 'contained',
color: 'primary'
}}
linkProps={{
href: '/products/123',
onNavigate: (href) => router.push(href)
}}
/>

Block Override Pattern:

<ListProductsGrid
listProductsGridTitle="Shop Collection"
subtitle="Curated Items"
>
{({defaultBlocks}) => ({
blocks: {
...defaultBlocks,
title: customTitle,
items: customItems,
pagination: customPagination,
},
blockOrder: ['title', 'items', 'pagination'],
})}
</ListProductsGrid>

πŸ”§ TypeScript Support​

Full TypeScript support with comprehensive type definitions:

import {ListProductsGrid} from '@nodeblocks/frontend-list-products-grid-block';
import {ReactElement} from 'react';
import {ChipProps, ButtonProps, IconButtonProps} from '@mui/material';

// Product grid item interface
interface ProductGridItem {
id: string;
title: string;
description?: string;
price: string;
originalPrice?: string;
imageUrl: string;
badges?: string[];
rating?: number;
reviewCount?: number;
isNew?: boolean;
isFeatured?: boolean;
}

// Link props for card navigation
interface LinkProps {
href?: string;
onClick?: (e: React.MouseEvent) => void;
onNavigate: ((href: string) => void) | 'standard-html-link';
openInNewTab?: boolean;
}

// Status object type
interface StatusObject {
label: string;
color?: 'default' | 'primary';
action?: Partial<ButtonProps> & {
href?: string;
onNavigate?: ((href: string) => void) | 'standard-html-link';
openInNewTab?: boolean;
};
}

// Grid card props type
interface GridCardProps {
title: string;
subtitle?: string;
subtitleImageUrl?: string;
summary?: string;
imageUrl?: string;
tertiaryText?: string;
content?: string;
chips?: (ChipProps & {
leftIcon?: ReactElement;
rightIcon?: ReactElement;
label: string;
})[];
tags?: {icon?: ReactElement; label: string | string[]}[];
titleIcon?: ReactElement;
titleAction?: Partial<IconButtonProps>;
button?: Partial<ButtonProps>;
status?: StatusObject;
linkProps?: LinkProps;
hasDivider?: boolean;
disabled?: boolean;
}

function TypedListProductsGrid() {
const productData: ProductGridItem[] = [
{
id: 'prod-1',
title: 'Premium Laptop',
description: '15" display, 16GB RAM, 512GB SSD',
price: '$1,299.99',
imageUrl: 'https://placehold.co/600x400',
badges: ['New'],
rating: 4.8,
reviewCount: 256,
},
{
id: 'prod-2',
title: 'Wireless Charger',
description: 'Fast charging, compatible with all Qi devices',
price: '$39.99',
imageUrl: 'https://placehold.co/600x400',
rating: 4.5,
reviewCount: 1024,
},
];

const handleNavigate = (href: string): void => {
console.log('Navigate to:', href);
};

return (
<ListProductsGrid
listProductsGridTitle="Our Products"
subtitle="Premium selection of electronics"
sx={{
maxWidth: 1200,
mx: 'auto',
p: 3,
}}
>
<ListProductsGrid.Title />
<ListProductsGrid.Items>
{productData.map(product => (
<ListProductsGrid.Items.GridCard
key={product.id}
title={product.title}
imageUrl={product.imageUrl}
summary={product.description}
chips={product.badges?.map(b => ({label: b}))}
linkProps={{href: `/products/${product.id}`, onNavigate: handleNavigate}}
button={{children: product.price}}
/>
))}
</ListProductsGrid.Items>
</ListProductsGrid>
);
}

πŸ“ Notes​

  • The main component extends MUI StackProps with default spacing={5} and padding px: 2, py: 5
  • ListProductsGrid.Title displays the subtitle above the main title with Typography components
  • ListProductsGrid.Items.GridCard requires a title prop; all other props are optional
  • When linkProps is provided, the entire card becomes clickable via CardActionArea
  • The onNavigate prop can be set to 'standard-html-link' for native browser navigation
  • status.action renders as a button when linkProps is present (to avoid nested <a> tags)
  • chips support MUI ChipProps plus optional leftIcon and rightIcon elements
  • tags with array labels are joined with " / " separator (e.g., ['A', 'B'] β†’ "A / B")
  • Card images have a fixed height of 120px with object-fit: cover
  • Disabled cards have reduced opacity (0.6) and pointer events disabled

Built with ❀️ using React, TypeScript, and MUI.