primefaces / primefaces/primereact

Virtual scroll bar not working as expected

Open
#8,375 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Status: Needs Triage
Dominant language
CSS
Stars
8.3k
Forks
1.2k
PR merge metrics
No merged PRs in 30d

Description

The virtiual scroll bar is failing to adopt to my styles its only working when i apply card
if i dont put class card it gets hidden i se nothing rendered

 // <div className="flex-1 overflow-hidden">
                        <div className="card flex justify-content-center">
                            <VirtualScroller
                                items={agentsData}
                                itemSize={80}
                                itemTemplate={agentItemTemplate}
                            // className="h-full"
                            // style={{ height: '100%' }}
                            // className="border-1 surface-border border-round"
                            // style={{ width: '200px', height: '200px' }}
                            />
                        </div>

here is my full code

'use client'

import React, { useState } from "react";
import { Card } from "primereact/card";
import { Button } from "primereact/button";
import { InputText } from "primereact/inputtext";
import { VirtualScroller, VirtualScrollerTemplateOptions } from 'primereact/virtualscroller';
import { useInfiniteQuery } from "@tanstack/react-query";
import { ProgressSpinner } from "primereact/progressspinner";

import MaterialUiLoaderLottie from "@/assets/nice-lotties/material-ui-loading-lottie.json";
import SnailErrorLottie from "@/assets/nice-lotties/snail-error-lottie.json";
// import SateLiteLottie from "@/assets/nice-lotties/satelite-loading-lottie.json";
// import FileLoadingLottie from "@/assets/nice-lotties/FileLoadingLottie.json";
import SkeletonLoadingLottie from "@/assets/nice-lotties/SkeletonLoadingLottie.json";
import NoDataLottie from "@/assets/nice-lotties/nodata.json";

import { getAllAgents } from "@/services/agents/agents-service";
import useHandleQueryError from "@/hooks/useHandleQueryError";

import dynamic from "next/dynamic";
const Lottie = dynamic(() => import("lottie-react"), { ssr: false });

interface Agent {
    id: number;
    name: string;
    code?: string;
    email?: string;
    phone?: string;
    status?: string;
    created_at?: string;
}

function UserAgentsListing() {
    const [globalSearch, setGlobalSearch] = useState("");
    const [globalSearchTerm, setGlobalSearchTerm] = useState("");

    // Fetch Agents data using useInfiniteQuery
    const { data, error, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage, status, } = useInfiniteQuery({
        queryKey: ["user-agents", "paginate", globalSearchTerm],
        queryFn: ({ pageParam = 1 }) => getAllAgents({ page: pageParam, search: globalSearchTerm, paginate: true }),
        getNextPageParam: (queryData) => {
            console.log("🚀 ~ UserAgentsListing ~ queryData:", queryData);
            const pageData = queryData?.data?.data;
            return pageData?.current_page < pageData?.last_page ? pageData.current_page + 1 : undefined;
        },
        initialPageParam: 1,
    });


    const isError = status === "error";
    const isPending = status === "pending";

    useHandleQueryError({ isError, error });

    // Flatten the paginated data
    const agentsData = data?.pages?.flatMap(page => page?.data?.data?.data) || [];

    // Search function
    const handleSearch = () => {
        setGlobalSearchTerm(globalSearch);
    };

    // Agent item template for VirtualScroller
    const agentItemTemplate = (agent: Agent, options: VirtualScrollerTemplateOptions) => {
        return (
            <div className="border-b border-gray-200 dark:border-gray-700 p-3 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
                <div className="flex items-start justify-between gap-3">
                    <div className="flex-1 min-w-0">
                        <div className="flex items-center gap-2 mb-1">
                            <h4 className="text-sm font-semibold text-gray-800 dark:text-white truncate">
                                {agent.name}
                            </h4>
                            {agent.code && (
                                <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-100">
                                    {agent.code}
                                </span>
                            )}
                        </div>

                        {agent.email && (
                            <p className="text-xs text-gray-600 dark:text-gray-400 truncate">
                                📧 {agent.email}
                            </p>
                        )}

                        {agent.phone && (
                            <p className="text-xs text-gray-600 dark:text-gray-400 truncate">
                                📱 {agent.phone}
                            </p>
                        )}
                    </div>

                    {agent.status && (
                        <span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium flex-shrink-0 ${agent.status === 'active'
                            ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100'
                            : 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100'
                            }`}>
                            {agent.status}
                        </span>
                    )}
                </div>
            </div>
        );
    };

    return (
        <div className="h-full">
            {isError ? (
                <div className="flex justify-center items-center h-full">
                    <div className="max-w-xs">
                        <Lottie animationData={SnailErrorLottie} loop autoplay />
                    </div>
                </div>
            ) : (
                <div className="h-full flex flex-col">
                    {/* Search Box */}
                    <div className="p-3 border-b border-gray-200 dark:border-gray-700">
                        <div className="p-inputgroup">
                            <InputText
                                type="search"
                                value={globalSearch}
                                onChange={(e) => setGlobalSearch(e.target.value)}
                                placeholder="Search agents by name, code..."
                                className="text-sm"
                            />
                            <Button
                                icon="pi pi-search"
                                className="p-button-primary"
                                onClick={handleSearch}
                                size="small"
                            />
                        </div>
                    </div>

                    {/* Agents List with VirtualScroller */}
                    {agentsData.length === 0 && !isPending ? (
                        <div className="flex justify-center items-center flex-1">
                            <div className="max-w-xs">
                                <Lottie animationData={NoDataLottie} loop autoplay />
                                <p className="text-center text-sm text-gray-600 dark:text-gray-400 mt-2">
                                    No agents assigned
                                </p>
                            </div>
                        </div>
                    ) : (
                        // <div className="flex-1 overflow-hidden">
                        <div className="card flex justify-content-center">
                            <VirtualScroller
                                items={agentsData}
                                itemSize={80}
                                itemTemplate={agentItemTemplate}
                                // className="h-full"
                                // style={{ height: '100%' }}
                                className="border-1 surface-border border-round"
                                style={{ width: '200px', height: '200px' }}
                            />
                        </div>
                    )}

                    {/* Loading Spinner */}
                    {isPending && (
                        <div className="flex justify-center items-center p-4 border-t border-gray-200 dark:border-gray-700">
                            <ProgressSpinner style={{ width: "25px", height: "25px" }} />
                            <span className="ml-2 text-sm">Loading agents...</span>
                        </div>
                    )}

                    {/* Load More Button */}
                    {hasNextPage && (
                        <div className="p-3 border-t border-gray-200 dark:border-gray-700">
                            <Button
                                label={isFetchingNextPage ? "Loading more agents..." : "Load More"}
                                className="w-full p-button-outlined p-button-sm"
                                icon={isFetchingNextPage ? "pi pi-spinner pi-spin" : "pi pi-chevron-down"}
                                onClick={() => fetchNextPage()}
                                disabled={isFetchingNextPage}
                                size="small"
                            />
                        </div>
                    )}

                    {!hasNextPage && agentsData.length > 0 && (
                        <div className="p-3 border-t border-gray-200 dark:border-gray-700">
                            <Button
                                label="All agents loaded"
                                className="w-full p-button-secondary p-button-sm"
                                disabled
                                size="small"
                            />
                        </div>
                    )}
                </div>
            )}
        </div>
    );
}

export default UserAgentsListing;

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the reported behavior in the UserAgentsListing component, focusing on the VirtualScroller container and its commented sizing classes and styles. Compare rendering with and without the card wrapper, and verify that the scroller remains visible and adopts the intended dimensions without relying on that wrapper.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, tailwindcss, typescript
Domain
frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.