react-plock

repository·main·Indexed 20 days ago

https://github.com/askides/react-plock

An ultra-small (<1kB gzipped), tree-shakeable library for creating responsive masonry layouts in React applications. It provides a Masonry component that supports both a default chunked layout and a balanced layout to minimize height differences between columns. Key features include responsive configuration for columns and gaps via media query breakpoints and a flexible render prop for defining item UI.

Tokens
2.2K
Snippets
10
Records
14
Agent score
70%

What's inside react-plock

  1. Enable Balanced Layout for harmonious grids

    main

    By default, the masonry layout distributes items sequentially. To create a more visually harmonious grid that minimizes height differences between columns, set useBalancedLayout: true in the config object. This is ideal for content with varying heights like images or cards.

    <Masonry
      items={items}
      config={{
        columns: [2, 3, 4],
        gap: [16, 16, 16],
        media: [640, 768, 1024],
        useBalancedLayout: true, // Enable balanced layout
      }}
      render={(item) => (
        <img src={item.url} alt={item.alt} style={{ width: '100%' }} />
      )}
    />
  2. Configure balanced vs chunked layout in Masonry

    main

    The Masonry component uses two different strategies to distribute items into columns:

    1. Chunked Layout (Default): Uses createChunks and createDataColumns. Items are grouped into rows of a specific size and then distributed into columns. This is faster but can result in uneven column heights if items have varying heights.
    2. Balanced Layout: Triggered by setting useBalancedLayout: true in the config. It uses createBalancedColumns to track the height of each item (via getBoundingClientRect) and assigns the next item to the currently shortest column. This results in much more even column heights but requires an extra render pass to measure heights.
  3. Ensure array lengths match for responsive configurations

    main

    When providing arrays for columns or gap to create a responsive layout, the number of elements in those arrays MUST be equal to the number of elements in the media array. Failing to match these lengths will cause rendering issues.

    // Correct: 3 breakpoints
    <Masonry
      config={{
        columns: [1, 2, 3],
        gap: [12, 16, 20],
        media: [640, 768, 1024],
      }}
    />
    
    // Correct: Fixed columns (no media array needed)
    <Masonry
      config={{
        columns: 4,
        gap: 8
      }}
    />
    
    // NOT Correct: Mismatched array lengths
    <Masonry
      config={{
        columns: [4],
        media: [640, 768],
      }}
    />
  4. Create a masonry grid with the Masonry component

    main

    Use the Masonry component to render a responsive masonry layout. You provide an array of items, a config object for layout rules, and a render function to define how each item is displayed.

    import { Masonry } from 'react-plock';
    
    const ImagesMasonry = () => {
      const items = [...imageUrls];
    
      return (
        <Masonry
          items={items}
          config={{
            columns: [1, 2, 3],
            gap: [24, 12, 6],
            media: [640, 768, 1024],
          }}
          render={(item, idx) => (
            <img key={idx} src={item} style={{ width: '100%', height: 'auto' }} />
          )}
        />
      );
    };
  5. MasonryProps Reference

    main

    The Masonry component accepts the following props:

    • items: T[]: A generic array of elements to be rendered.
    • render: (item: T, idx: number) => React.ReactNode: A render prop that defines the UI for each tile. It receives the current item and its relative index.
    • config: MasonryConfig: An object defining layout behavior.
    • as?: React.ElementType: The HTML element or component to use as the container (defaults to div).
    • ...otherProps: Any standard div attributes (e.g., id, className). Note that the style prop will be overwritten by the internal masonry engine.
    export type MasonryProps<T> = React.ComponentPropsWithoutRef<'div'> & {
      items: T[];
      render: (item: T, idx: number) => React.ReactNode;
      config: {
        columns: number | number[];
        gap: number | number[];
        media?: number[];
        useBalancedLayout?: boolean;
      };
      as?: React.ElementType;
    };
  6. Configure Masonry layout via the config object

    main

    The config object controls the responsiveness and spacing of the grid:

    • columns: A single number for a fixed column count, or an array of numbers for responsive breakpoints.
    • gap: A single number for a fixed gap, or an array of numbers for responsive breakpoints.
    • media?: An array of numbers representing media query breakpoints. If columns or gap are arrays, the length of media must match the number of breakpoints provided.
  7. Create balanced columns with createBalancedColumns

    main

    The createBalancedColumns utility distributes items into a specified number of columns by always picking the shortest column to place the next item. This requires a getHeight callback to determine the height of each item.

    Signature: createBalancedColumns<T>(items: T[], columns: number, getHeight: (item: T) => number): T[][]

    const columns = createBalancedColumns(
      items, 
      3, 
      (item) => item.height
    );
  8. Use the Masonry component

    main

    The Masonry component renders a grid of items in a masonry layout. It supports responsive configurations for columns and gaps via the config prop and can switch between a standard chunked layout and a balanced layout based on the useBalancedLayout flag.

    Props

    • items: An array of data items to render.
    • render: A function (item: T, idx: number) => React.ReactNode that defines how each item is rendered.
    • config: An object containing:
      • columns: A number or array of numbers defining the column count.
      • gap: A number or array of numbers defining the spacing between items.
      • media (optional): An array of media query breakpoints to trigger responsive changes.
      • useBalancedLayout (optional): A boolean. If true, items are distributed into columns based on their actual rendered height to keep columns even. If false (default), items are distributed in chunks.
    • as (optional): The HTML element or React component to use as the container (defaults to 'div').
    • ...rest: Any other standard div props.
    <Masonry
      items={myData}
      render={(item) => <Card data={item} />}
      config={{
        columns: [1, 2, 3], // 1 col on mobile, 2 on tablet, 3 on desktop
        gap: 16,
        media: [768, 1024],
        useBalancedLayout: true
      }}
    />