reactjsreact-virtualized

How can I add margin (space between each box) to all my rendered items in react virtualized grid?


I use react virtualized to show some items. My problem is now how can I add margin for each box to have space between every box ?

here is a sandbox you see all boxes are bordered and have no space. How can I add space ?

https://codesandbox.io/p/sandbox/react-virtualized-responsive-card-grid-w-infinite-scroll-forked-8kmr8t?file=%2Fsrc%2FApp.tsx

and here is my list code

export function VirtualizedGrid<ItemType>({
  items,
  renderItem,
  itemHeight,
  itemMinWidth,
  numColumns,
  registerChild,
  onRowsRendered
}: VirtualizedGridProps<ItemType>): JSX.Element {
  const gridRef = useRef<any>(null);
  const containerRef = useRef<any>(null);
  const containerWidth = containerRef?.current?.clientWidth ?? 0;

  const windowSize = useWindowSize();

  useEffect(() => {
    gridRef.current?.recomputeGridSize();
  }, [windowSize]);

  function calculateColumnCount(width: number) {
    return Math.floor(width / itemMinWidth);
  }

  function calculateItemWidth(width: number, columnCount: number) {
    return width / columnCount;
  }

  const columnCount = numColumns ?? calculateColumnCount(containerWidth);
  const rowCount = Math.ceil(items.length / columnCount);
  const itemWidth = calculateItemWidth(containerWidth, columnCount);

  return (
    <Container ref={containerRef}>
      <WindowScroller>
        {({ height, isScrolling, onChildScroll, scrollTop }) => (
          <AutoSizer disableHeight>
            {() => {
              return (
                <Grid
                  // ref={gridRef}
                  ref={(el) => {
                    registerChild(el);
                    gridRef.current = el;
                  }}
                  autoHeight
                  columnCount={columnCount}
                  columnWidth={itemWidth}
                  width={containerWidth}
                  height={height}
                  rowCount={rowCount}
                  rowHeight={itemHeight}
                  isScrolling={isScrolling}
                  scrollTop={scrollTop}
                  onScroll={onChildScroll}
                  cellRenderer={(props: GridCellProps) => {
                    const fullProps: VirtualizedGridItemProps<ItemType> = {
                      ...props,
                      items,
                      columnCount: columnCount
                    };
                    return renderItem(fullProps);
                  }}
                />
              );
            }}
          </AutoSizer>
        )}
      </WindowScroller>
    </Container>
  );
}


Solution

  • Just add conditional padding based on items indexes to the Container element of your TestGridItem.tsx.

    Here is Sandbox example based on your code

    import { motion } from "framer-motion";
    import React from "react";
    import styled from "styled-components";
    
    import { VirtualizedGridItemProps } from "./interfaces";
    
    /**
     * Interfaces
     */
    
    interface TestObject {
      id: number;
      name: string;
    }
    
    export interface TestGridItemProps
      extends VirtualizedGridItemProps<TestObject> {}
    
    /**
     * Styles
     */
    
    const GAP_BETWEEN_ITEMS = "10px";
    
    const Container = styled.div<{
      isFirstCol: boolean;
      isLastCol: boolean;
      isFirstRow: boolean;
    }>`
      display: flex;
      padding-left: ${(props) => (props.isFirstCol ? "0px" : GAP_BETWEEN_ITEMS)};
      padding-top: ${(props) => (props.isFirstRow ? "0px" : GAP_BETWEEN_ITEMS)};
    `;
    
    const Card = styled(motion.div)`
      background: #111111;
      border: 1px solid rgba(255, 255, 255, 0.1);
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      flex: 1;
      height: 100%;
      font-family: sans-serif;
      font-weight: 600;
      text-align: center;
      padding: 12px;
    `;
    
    /**
     * Component
     */
    
    export function TestGridItem({
      items,
      columnCount,
      rowIndex,
      columnIndex,
      style,
    }: TestGridItemProps): JSX.Element {
      const index = rowIndex * columnCount + columnIndex;
    
      if (index > items.length - 1) {
        return <></>;
      }
    
      const isFirstCol = columnIndex === 0;
      const isLastCol = columnIndex === columnCount - 1;
      const isFirstRow = rowIndex === 0;
    
      return (
        <Container
          style={style}
          isFirstCol={isFirstCol}
          isLastCol={isLastCol}
          isFirstRow={isFirstRow}
        >
          <Card
            variants={{
              hidden: {
                opacity: 0,
              },
              visible: {
                opacity: 1,
              },
            }}
            initial="hidden"
            animate="visible"
          >
            {`${items[index].name} (ID: ${items[index].id})`}
          </Card>
        </Container>
      );
    }