DataView displays data in grid or list layout with pagination and sorting features.
import { DataView } from 'primereact/dataview';<DataView></DataView>DataView displays data in a customizable layout using an item template.
import { ProductService } from '@/services/product.service';
import Image from 'next/image';
import { Button } from 'primereact/button';
import { DataView } from 'primereact/dataview';
import { Tag } from 'primereact/tag';
import * as React from 'react';
interface Product {
id: string;
code: string;
name: string;
description: string;
image: string;
price: number;
category: string;
quantity: number;
inventoryStatus: string;
rating: number;
}
export default function BasicDemo() {
const [products, setProducts] = React.useState<Product[]>([]);
React.useEffect(() => {
ProductService.getProductsSmall().then((data) => setProducts(data.slice(0, 5)));
}, []);
const getSeverity = (product: Product) => {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return undefined;
}
};
return (
<div className="card">
<DataView>
<div className="flex flex-col">
{products.map((product, index) => (
<div key={index} className={`flex flex-col sm:flex-row sm:items-center p-6 gap-4 ${index !== 0 ? 'border-t border-surface-200 dark:border-surface-700' : ''}`}>
<div className="md:w-40 relative">
<Image className="mx-auto rounded w-full" src={`https://primefaces.org/cdn/primevue/images/product/${product.image}`} alt={product.name} width={160} height={160} />
<div className="absolute bg-black/70 rounded-border" style={{ left: '4px', top: '4px' }}>
<Tag severity={getSeverity(product)}>
<Tag.Label>{product.inventoryStatus}</Tag.Label>
</Tag>
</div>
</div>
<div className="flex flex-col md:flex-row justify-between md:items-center flex-1 gap-6">
<div className="flex flex-row md:flex-col justify-between items-start gap-2">
<div>
<span className="font-medium text-surface-500 dark:text-surface-400 text-sm">{product.category}</span>
<div className="text-lg font-medium mt-2">{product.name}</div>
</div>
<div className="bg-surface-100 p-1" style={{ borderRadius: '30px' }}>
<div
className="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2"
style={{
borderRadius: '30px',
boxShadow: '0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)'
}}
>
<span className="text-surface-900 font-medium text-sm">{product.rating}</span>
<i className="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div className="flex flex-col md:items-end gap-8">
<span className="text-xl font-semibold">${product.price}</span>
<div className="flex flex-row-reverse md:flex-row gap-2">
<Button variant="outlined">
<i className="pi pi-heart"></i>
</Button>
<Button disabled={product.inventoryStatus === 'OUTOFSTOCK'} className="flex-auto md:flex-initial whitespace-nowrap">
<i className="pi pi-shopping-cart"></i>
Buy Now
</Button>
</div>
</div>
</div>
</div>
))}
</div>
</DataView>
</div>
);
}DataView supports pagination to navigate through large datasets efficiently. Refer to the Paginator for more information about customizing the paginator.
import { ProductService } from '@/services/product.service';
import { usePaginatorChangeEvent } from '@primereact/types/shared/paginator';
import Image from 'next/image';
import { Button } from 'primereact/button';
import { DataView } from 'primereact/dataview';
import { Paginator } from 'primereact/paginator';
import { Tag } from 'primereact/tag';
import * as React from 'react';
interface Product {
id: string;
code: string;
name: string;
description: string;
image: string;
price: number;
category: string;
quantity: number;
inventoryStatus: string;
rating: number;
}
export default function PaginationDemo() {
const [products, setProducts] = React.useState<Product[]>([]);
const [page, setPage] = React.useState(1);
const itemsPerPage = 5;
React.useEffect(() => {
ProductService.getProductsSmall().then((data) => setProducts(data));
}, []);
const getSeverity = (product: Product) => {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return undefined;
}
};
return (
<div className="card">
<DataView>
<div className="flex flex-col">
{products.slice((page - 1) * itemsPerPage, page * itemsPerPage).map((product, index) => (
<div key={index} className={`flex flex-col sm:flex-row sm:items-center p-6 gap-4 ${index !== 0 ? 'border-t border-surface-200 dark:border-surface-700' : ''}`}>
<div className="md:w-40 relative">
<Image className="mx-auto rounded w-full" src={`https://primefaces.org/cdn/primevue/images/product/${product.image}`} alt={product.name} width={160} height={160} />
<div className="absolute bg-black/70 rounded-border" style={{ left: '4px', top: '4px' }}>
<Tag severity={getSeverity(product)}>
<Tag.Label>{product.inventoryStatus}</Tag.Label>
</Tag>
</div>
</div>
<div className="flex flex-col md:flex-row justify-between md:items-center flex-1 gap-6">
<div className="flex flex-row md:flex-col justify-between items-start gap-2">
<div>
<span className="font-medium text-surface-500 dark:text-surface-400 text-sm">{product.category}</span>
<div className="text-lg font-medium mt-2">{product.name}</div>
</div>
<div className="bg-surface-100 p-1" style={{ borderRadius: '30px' }}>
<div
className="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2"
style={{
borderRadius: '30px',
boxShadow: '0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)'
}}
>
<span className="text-surface-900 font-medium text-sm">{product.rating}</span>
<i className="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div className="flex flex-col md:items-end gap-8">
<span className="text-xl font-semibold">${product.price}</span>
<div className="flex flex-row-reverse md:flex-row gap-2">
<Button variant="outlined">
<i className="pi pi-heart"></i>
</Button>
<Button disabled={product.inventoryStatus === 'OUTOFSTOCK'} className="flex-auto md:flex-initial whitespace-nowrap">
<i className="pi pi-shopping-cart"></i>
Buy Now
</Button>
</div>
</div>
</div>
</div>
))}
</div>
<Paginator total={products.length} itemsPerPage={itemsPerPage} onPageChange={(e: usePaginatorChangeEvent) => setPage(e.value)} className="border-t border-surface-200 dark:border-surface-700 pt-4">
<Paginator.Content>
<Paginator.First />
<Paginator.Prev />
<Paginator.Pages />
<Paginator.Next />
<Paginator.Last />
</Paginator.Content>
</Paginator>
</DataView>
</div>
);
}DataView provides sorting functionality to order items based on selected criteria.
import { ProductService } from '@/services/product.service';
import { useDataView } from '@primereact/headless/dataview';
import type { ToggleButtonGroupValueChangeEvent } from '@primereact/types/shared/togglebutton';
import Image from 'next/image';
import { Button } from 'primereact/button';
import { DataView } from 'primereact/dataview';
import { Tag } from 'primereact/tag';
import { ToggleButton } from 'primereact/togglebutton';
import * as React from 'react';
interface Product {
id: string;
code: string;
name: string;
description: string;
image: string;
price: number;
category: string;
quantity: number;
inventoryStatus: string;
rating: number;
}
export default function SortDemo() {
const [products, setProducts] = React.useState<Product[]>([]);
const [value, setValue] = React.useState<string | null>(null);
const { sort } = useDataView();
React.useEffect(() => {
ProductService.getProductsSmall().then((data) => setProducts(data.slice(0, 5)));
}, []);
const getSeverity = (product: Product) => {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return undefined;
}
};
const onSortChange = (value: string | null) => {
const sortOrder = value === 'hightolow' ? -1 : value === 'lowtohigh' ? 1 : 0;
setValue(value);
setProducts((prev) => (sort([...prev], 'price', sortOrder) as Product[]) ?? []);
};
return (
<div className="card">
<DataView>
<div className="flex justify-center border-b border-surface-200 dark:border-surface-700 pb-4">
<ToggleButton.Group value={value} onValueChange={(e: ToggleButtonGroupValueChangeEvent) => onSortChange(e.value as string)} allowEmpty={false}>
<ToggleButton value="hightolow">
<ToggleButton.Indicator>Price High to Low</ToggleButton.Indicator>
</ToggleButton>
<ToggleButton value="lowtohigh">
<ToggleButton.Indicator>Price Low to High</ToggleButton.Indicator>
</ToggleButton>
</ToggleButton.Group>
</div>
<div className="flex flex-col">
{products.map((product, index) => (
<div key={index} className={`flex flex-col sm:flex-row sm:items-center p-6 gap-4 ${index !== 0 ? 'border-t border-surface-200 dark:border-surface-700' : ''}`}>
<div className="md:w-40 relative">
<Image className="mx-auto rounded w-full" src={`https://primefaces.org/cdn/primevue/images/product/${product.image}`} alt={product.name} width={160} height={160} />
<div className="absolute bg-black/70 rounded-border" style={{ left: '4px', top: '4px' }}>
<Tag severity={getSeverity(product)}>
<Tag.Label>{product.inventoryStatus}</Tag.Label>
</Tag>
</div>
</div>
<div className="flex flex-col md:flex-row justify-between md:items-center flex-1 gap-6">
<div className="flex flex-row md:flex-col justify-between items-start gap-2">
<div>
<span className="font-medium text-surface-500 dark:text-surface-400 text-sm">{product.category}</span>
<div className="text-lg font-medium mt-2">{product.name}</div>
</div>
<div className="bg-surface-100 p-1" style={{ borderRadius: '30px' }}>
<div
className="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2"
style={{
borderRadius: '30px',
boxShadow: '0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)'
}}
>
<span className="text-surface-900 font-medium text-sm">{product.rating}</span>
<i className="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div className="flex flex-col md:items-end gap-8">
<span className="text-xl font-semibold">${product.price}</span>
<div className="flex flex-row-reverse md:flex-row gap-2">
<Button variant="outlined">
<i className="pi pi-heart"></i>
</Button>
<Button disabled={product.inventoryStatus === 'OUTOFSTOCK'} className="flex-auto md:flex-initial whitespace-nowrap">
<i className="pi pi-shopping-cart"></i>
Buy Now
</Button>
</div>
</div>
</div>
</div>
))}
</div>
</DataView>
</div>
);
}DataView offers multiple layout options to display items in grid or list format.
import { ProductService } from '@/services/product.service';
import type { ToggleButtonGroupValueChangeEvent } from '@primereact/types/shared/togglebutton';
import Image from 'next/image';
import { Button } from 'primereact/button';
import { DataView } from 'primereact/dataview';
import { Tag } from 'primereact/tag';
import { ToggleButton } from 'primereact/togglebutton';
import * as React from 'react';
interface Product {
id: string;
code: string;
name: string;
description: string;
image: string;
price: number;
category: string;
quantity: number;
inventoryStatus: string;
rating: number;
}
export default function LayoutDemo() {
const [products, setProducts] = React.useState<Product[]>([]);
const [value, setValue] = React.useState<string>('grid');
React.useEffect(() => {
ProductService.getProductsSmall().then((data) => setProducts(data.slice(0, 12)));
}, []);
const getSeverity = (product: Product) => {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return undefined;
}
};
const listLayout = () => {
return (
<div className="flex flex-col">
{products.map((product, index) => (
<div key={index} className={`flex flex-col sm:flex-row sm:items-center p-6 gap-4 ${index !== 0 ? 'border-t border-surface-200 dark:border-surface-700' : ''}`}>
<div className="md:w-40 relative">
<Image className="mx-auto rounded w-full" src={`https://primefaces.org/cdn/primevue/images/product/${product.image}`} alt={product.name} width={160} height={160} />
<div className="absolute bg-black/70 rounded-border" style={{ left: '4px', top: '4px' }}>
<Tag severity={getSeverity(product)}>
<Tag.Label>{product.inventoryStatus}</Tag.Label>
</Tag>
</div>
</div>
<div className="flex flex-col md:flex-row justify-between md:items-center flex-1 gap-6">
<div className="flex flex-row md:flex-col justify-between items-start gap-2">
<div>
<span className="font-medium text-surface-500 dark:text-surface-400 text-sm">{product.category}</span>
<div className="text-lg font-medium mt-2">{product.name}</div>
</div>
<div className="bg-surface-100 p-1" style={{ borderRadius: '30px' }}>
<div
className="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2"
style={{
borderRadius: '30px',
boxShadow: '0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)'
}}
>
<span className="text-surface-900 font-medium text-sm">{product.rating}</span>
<i className="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div className="flex flex-col md:items-end gap-8">
<span className="text-xl font-semibold">${product.price}</span>
<div className="flex flex-row-reverse md:flex-row gap-2">
<Button variant="outlined">
<i className="pi pi-heart"></i>
</Button>
<Button disabled={product.inventoryStatus === 'OUTOFSTOCK'} className="flex-auto md:flex-initial whitespace-nowrap">
<i className="pi pi-shopping-cart"></i>
Buy Now
</Button>
</div>
</div>
</div>
</div>
))}
</div>
);
};
const gridLayout = () => {
return (
<div className="grid grid-cols-12 gap-4">
{products.map((product, index) => {
return (
<div key={index} className="col-span-12 sm:col-span-6 md:col-span-4 xl:col-span-6 p-2">
<div className="p-6 border border-surface-200 dark:border-surface-700 bg-surface-0 dark:bg-surface-900 rounded flex flex-col">
<div className="bg-surface-50 flex justify-center rounded p-4">
<div className="relative mx-auto">
<Image src={`https://primefaces.org/cdn/primevue/images/product/${product.image}`} alt={product.name} width={300} height={200} className="rounded" />
<div className="absolute bg-black/70 rounded-border" style={{ left: '4px', top: '4px' }}>
<Tag severity={getSeverity(product)}>
<Tag.Label>{product.inventoryStatus}</Tag.Label>
</Tag>
</div>
</div>
</div>
<div className="pt-6">
<div className="flex flex-row justify-between items-start gap-2">
<div>
<span className="font-medium text-surface-500 dark:text-surface-400 text-sm">{product.category}</span>
<div className="text-lg font-medium mt-1">{product.name}</div>
</div>
<div className="bg-surface-100 p-1" style={{ borderRadius: '30px' }}>
<div
className="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2"
style={{
borderRadius: '30px',
boxShadow: '0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)'
}}
>
<span className="text-surface-900 font-medium text-sm">{product.rating}</span>
<i className="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div className="flex flex-col gap-6 mt-6">
<span className="text-2xl font-semibold">${product.price}</span>
<div className="flex gap-2">
<Button disabled={product.inventoryStatus === 'OUTOFSTOCK'} className="flex-auto whitespace-nowrap">
<i className="pi pi-shopping-cart"></i>
Buy Now
</Button>
<Button variant="outlined">
<i className="pi pi-heart"></i>
</Button>
</div>
</div>
</div>
</div>
</div>
);
})}
</div>
);
};
const list = listLayout();
const grid = gridLayout();
return (
<div className="card">
<DataView>
<div className="flex justify-end border-b border-surface-200 dark:border-surface-700 pb-4">
<ToggleButton.Group value={value} onValueChange={(e: ToggleButtonGroupValueChangeEvent) => setValue(e.value as string)} allowEmpty={false}>
<ToggleButton value="list">
<ToggleButton.Indicator>
<i className="pi pi-bars"></i>
</ToggleButton.Indicator>
</ToggleButton>
<ToggleButton value="grid">
<ToggleButton.Indicator>
<i className="pi pi-table"></i>
</ToggleButton.Indicator>
</ToggleButton>
</ToggleButton.Group>
</div>
{value === 'list' ? list : grid}
</DataView>
</div>
);
}DataView shows a loading state while data is being fetched or processed.
import type { ToggleButtonGroupValueChangeEvent } from '@primereact/types/shared/togglebutton';
import { DataView } from 'primereact/dataview';
import { Skeleton } from 'primereact/skeleton';
import { ToggleButton } from 'primereact/togglebutton';
import * as React from 'react';
export default function LayoutDemo() {
const [value, setValue] = React.useState<string>('grid');
const listLayout = () => {
return (
<div className="flex flex-col">
{Array.from({ length: 6 }, (_, i) => (
<div key={i} className={`flex flex-col xl:flex-row xl:items-start p-6 gap-6 ${i !== 0 ? 'border-t border-surface-200 dark:border-surface-700' : ''}`}>
<Skeleton className="!w-9/12 sm:!w-64 xl:!w-40 !h-24 mx-auto" />
<div className="flex flex-col sm:flex-row justify-between items-center xl:items-start flex-1 gap-6">
<div className="flex flex-col items-center sm:items-start gap-4">
<Skeleton width="8rem" height="2rem" />
<Skeleton width="6rem" height="1rem" />
<div className="flex items-center gap-4">
<Skeleton width="6rem" height="1rem" />
<Skeleton width="3rem" height="1rem" />
</div>
</div>
<div className="flex sm:flex-col items-center sm:items-end gap-4 sm:gap-2">
<Skeleton width="4rem" height="2rem" />
<Skeleton size="3rem" shape="circle" />
</div>
</div>
</div>
))}
</div>
);
};
const gridLayout = () => {
return (
<div className="grid grid-cols-12 gap-4">
{Array.from({ length: 6 }, (_, i) => (
<div key={i} className="col-span-12 sm:col-span-6 xl:col-span-4 p-2">
<div className="p-6 border border-surface-200 dark:border-surface-700 bg-surface-0 dark:bg-surface-900 rounded">
<div className="flex flex-wrap items-center justify-between gap-2">
<Skeleton width="6rem" height="2rem" />
<Skeleton width="3rem" height="1rem" />
</div>
<div className="flex flex-col items-center gap-4 py-8">
<Skeleton width="75%" height="10rem" />
<Skeleton width="8rem" height="2rem" />
<Skeleton width="6rem" height="1rem" />
</div>
<div className="flex items-center justify-between">
<Skeleton width="4rem" height="2rem" />
<Skeleton width="6rem" height="1rem" shape="circle" size="3rem" />
</div>
</div>
</div>
))}
</div>
);
};
const list = listLayout();
const grid = gridLayout();
return (
<div className="card">
<DataView>
<div className="flex justify-end border-b border-surface-200 dark:border-surface-700 pb-4">
<ToggleButton.Group value={value} onValueChange={(e: ToggleButtonGroupValueChangeEvent) => setValue(e.value as string)} allowEmpty={false}>
<ToggleButton value="list">
<ToggleButton.Indicator>
<i className="pi pi-bars"></i>
</ToggleButton.Indicator>
</ToggleButton>
<ToggleButton value="grid">
<ToggleButton.Indicator>
<i className="pi pi-table"></i>
</ToggleButton.Indicator>
</ToggleButton>
</ToggleButton.Group>
</div>
{value === 'list' ? list : grid}
</DataView>
</div>
);
}