XMasonry: Masonry Layout for React JS

Overview

XMasonry: Masonry Layout for React JS

npm Dependencies Build Status npm License File Size File Size (GZip) GitHub

Responsive, minimalistic and full-featured native masonry layout (grid) for React JS.

Features

  • Native masonry layout implementation for React JS with no dependencies.
  • Minimalistic by design.
  • Responsive, mobile-friendly approach (so there is no "fixed block width in pixels" option).
  • Configurable width of blocks (in columns) and width of columns (targeting width in pixels), maximum number of columns, centering, etc.
  • Fully customizable using CSS. Put animations and transitions you like using .xmasonry and .xblock selectors.
  • Works with server rendering.

Demo

Check the XMasonry demos page. You can also see the notes application made with react-xmasonry. Play with this code pen to see what XMasonry can.

Table of Contents

  1. Installation
  2. Basic Usage
  3. Styling
    1. Animations & Transitions
    2. Server Rendering Note
  4. Configuring Components
    1. Properties
    2. Properties
    3. Accessing by Reference
  5. XMasonry Under the Hood
  6. License

Installation

npm install react-xmasonry --save-dev

Or, if you use the old-style ">

<script type="text/javascript" src="https://unpkg.com/react-xmasonry/dist/index.js">script>

Having trouble installing react-xmasonry? Check this issue or open a new one if you still struggling.

Usage

Import XMasonry and XBlock components:

import { XMasonry, XBlock } from "react-xmasonry"; // Imports precompiled bundle

The simplest layout using JSX and some styling may look like the following:

Simple Card

Any text!

Wider card

Any text!

} ">
render () {
    return <XMasonry>
        <XBlock>
            <div className="card">
                <h1>Simple Card</h1>
                <p>Any text!</p>
            </div>
        </XBlock>
        <XBlock width={ 2 }>
            <div className="card">
                <h1>Wider card</h1>
                <p>Any text!</p>
            </div>
        </XBlock>
    </XMasonry>
}

There is no more JavaScript than positioning and sizing! Use any CSS to make animations and transitions you like (.xmasonry and .xblock selectors). And all the further magic XMasonry will do for you. See the demos page sources here.

Styling

Animations and Transitions

If you want to put transitions/animations on XMasonry, using the .xmasonry and .xblock selectors. For example:

@keyframes comeIn {
    0% { transform: scale(0) }
    75% { transform: scale(1.03) }
    100% { transform: scale(1) }
}

.xmasonry .xblock {
    animation: comeIn ease 0.5s;
    animation-iteration-count: 1;
    transition: left .3s ease, top .3s ease;
}

.card {
    margin: 7px;
    padding: 5px;
    border-radius: 3px;
    box-shadow: 0 1px 3px darkgray;
}

Warning: do not apply any display/positioning/margin styles to .xblock selector. Instead, create a child element to XBlock, for example, .card, and put any styles you need to it. XBlock's dimensions are used in calculations and any styling like adding margins may create an unwanted result.

Warning: do not stick XBlock's content styling to .xblock selector. Use .xmasonry instead. See how XMasonry works to understand why: the .xblock class is applied only after the content measurements are done.

Server-Side Rendering

XMasonry, being rendered on the server (renderToStaticMarkup), will be unable to detect content heights due server rendering algorithm limitations. Nevertheless, rendering on the server is possible and won't affect anything (like SEO) but the consistent view with the client-rendered result. To make even this behavior configurable, XMasonry, when triggered to render contents on the server, puts additional .xmasonry-static and .xblock-static classes respectively, as well as changes some styles to make each XBlock render as a static-positioned block (by default). You can apply additional styles to this selector to make the server-rendered result look more consistent with the client's one, for example:

.xmasonry-static {
    text-align: center;
    overflow: auto;
}

.xblock-static {
    float: left;
    text-align: left;
}

You can disable SSR by using the following environment variable passed to your renderer:

REACT_XMASONRY_SSR_ENABLED=false

Configuring Components

There are several properties you can assign to XMasonry and XBlock components.

Component Properties

Property Default Description
center true A boolean value determining whether nested s should be centered if there are some empty columns left.
maxColumns Infinity A number identifying the maximum columns number.
responsive true A boolean value determining whether the layout should be responsive to window size changes.
smartUpdate true A boolean value indicating whether Smart Updates are enabled. Smart Update is an XMasonry feature that performs silent checks on XMasonry XBlocks sizes and updates the layout when any size changes are detected. These checks work in the next way: when any update on XMasonry happens, Smart Update will schedule sizes check through the 100 ms (default), then, if no sizes changed, through the 200 ms, 400 ms and so on. When any change happens, this procedure repeats, starting from 100 ms check. These checks and updates are highly optimized - use it for your convenience!
smartUpdateCeil Infinity A number in milliseconds which determines the maximum size check interval for XMasonry Smart Update. If you are just too lazy to update dynamic layout manually with update method, it's okay to set this prop to some value in milliseconds (for example, 1000 ms). After Smart Update checks interval reaches the specified value, it will start looping to continuously perform checks with smartUpdateCeil interval of time. All size checks are optimized and does not waste computing power.
targetBlockWidth 300 A number which determines the "target" width in pixels of the nested s. The layout takes all available space, and determines the number of columns using this value. For example, if container has 600 px of available width and we specify targetBlockWidth={200}, we will get exactly 3 columns of 200 px width. It will still be 3 columns if there is 660 pixels available, this time with each column taking 220 px. The simplified expression for number of columns is the following: Math.max(1, Math.round(containerWidth / targetBlockWidth)).
updateOnFontLoad true A boolean value determining whether the layout should be updated when fonts are loaded.
updateOnImagesLoad true A boolean value determining whether the layout should be updated when images finish loading. It normally takes a little while until images are loaded, and this causes incorrect blocks heights calculations at the beginning. This option allows to auto-update grid sizes when images complete loading. If layout contains no images, no handlers will be assigned.

Component Properties

Property Default Description
width 1 A number which determines nested block width in columns. If the number of columns available is less than the specified width, nested block will shrink to fit available space.

Accessing by Reference

You can access component by reference, but do it only if it is necessarily (for example, when inner content dynamically changes in size):

<XMasonry ref={ (x) => this.xMasonry = x }>
    // ...
</XMasonry>

Note that all the listed properties of component are read-only.

Ref Property Type Description
columns number The number of currently rendered columns.
container HTMLElement The
block containing the layout.
update function Trigger this function to update nested XBlocks sizes and positions. It is safe to trigger this function multiple times, updates are optimized. Technically, this function will check if any of containers changed its size and re-render XMasonry only if size was changed.

By default, XMasonry sniff and automatically update on the next events:

  1. Window size changes, see responsive prop.
  2. Font load events, see updateOnFontLoad prop.
  3. Image load events, see updateOnImagesLoad prop.
  4. Children changes like adding, replacing or deleting children.
  5. After any change in layout happens, see smartUpdate prop.

XMasonry Under the Hood

Technically, XMasonry component renders 3 times:

  1. "Empty Render" (ER), when XMasonry just renders its empty container and measures the available width;
  2. "Invisible Render" (IR), when XMasonry renders visibility: hidden blocks width computed column widths to measure their heights;
  3. And finally "Actual Render" (AR), when it renders elements with computed dimensions and positions. The .xblock style gets applied here only, so you can put animations on it.

This stages take around 3-4 frames to appear on the screen (~60ms).

Each time when elements change in masonry layout (images load or animation end, depending on initial configuration), the XMasonry update method is triggered. It goes through rendered elements this time, and looks for any size changes there. Thanks to React, all the DOM updates are optimized here and this function is very light to call. You can manually trigger XMasonry update function, whenever you need to update the layout. By default, after any change in layout, Smart Update will be performed. Check smartUpdate prop description for more information.

Once the window size gets changed (default behavior), the "force update" technique is applied, which do the IR and AR phases again.

License

MIT © Nikita Savchenko

Comments
  • prop `className` did not match. Server:

    prop `className` did not match. Server: "xmasonry xmasonry-static" Client: "xmasonry"

    Hi there,

    Getting this warning when I'm just returning an array of containing images.

    Warning: Prop className did not match. Server: "xmasonry xmasonry-static" Client: "xmasonry"

    Wondering if this is known.

    opened by Wayne-CO 14
  • Components are not rendering

    Components are not rendering

    Hi,

    Tried to use your library but the components are not rendering. Also I'm using VS Code and it can't find the definition for the XMasonry and XBlock components when I import them.

    Basically I have this:

    import { XMasonry, XBlock } from 'react-xmasonry';
    
    /* ... */
    return (
      <XMasonry>
        <XBlock>
          <Something />
        </XBlock>
        <XBlock>
          <Something />
        </XBlock>
      </XMasonry>
    )
    

    But the "Something" components are not appearing on screen. I'm using the React Dev Tools and the components are also not appearing there, and it doesn't throw any errors in the console. It's like is not in my code but I'm really sure I'm doing things right and the simple as I can.

    Some pics:

    image

    image

    opened by wuelcas 13
  • Unable to Import XMasonry to Meteor Project

    Unable to Import XMasonry to Meteor Project

    After addingimport { XMasonry, XBlock } from "react-xmasonry"; to a component, I get the following error:

    Uncaught Error: Cannot find module 'React'
        at makeMissingError (modules-runtime.js?hash=8587d18…:231)
        at require (modules-runtime.js?hash=8587d18…:241)
        at n (modules.js?hash=2355269…:220189)
        at index.js (modules.js?hash=2355269…:220189)
        at fileEvaluate (modules-runtime.js?hash=8587d18…:343)
        at require (modules-runtime.js?hash=8587d18…:238)
        at PinBoard2.js (PinBoard2.js:1)
        at fileEvaluate (modules-runtime.js?hash=8587d18…:343)
        at require (modules-runtime.js?hash=8587d18…:238)
        at routes.js (routes.js:1)
    

    Any insight on why this might be happening?

    Integration 
    opened by aogaili 12
  • [Feature Request]/[Help Needed] Custom breakpoints for responsive number of columns

    [Feature Request]/[Help Needed] Custom breakpoints for responsive number of columns

    Hi,

    I want to set the number of columns AND block width responsively so it always fills 100% of the container width

    Currently, I've tried to implement this by manipulating targetBlockWidth but it doesn't work reliably.

      // Using variable columnWidth`
          <XMasonry targetBlockWidth={columnWidth} responsive={false}>`
           {items}
         </XMasonry>
    
        const [columnWidth, setColumnWidth] = useState(300);
        // Setting responsive column widths where sizes.width is the container width
        const getWidth = () => {
          if (sizes.width < 480) {
            setColumnWidth(Math.floor(sizes.width / 2));
          } else if (sizes.width < 640) {
            setColumnWidth(Math.floor(sizes.width / 3));
          } else if (sizes.width < 1280) {
            setColumnWidth(Math.floor(sizes.width / 4));
          } else if (sizes.width < 1536) {
            setColumnWidth(Math.floor(sizes.width / 5));
          } else if (sizes.width >= 1536) {
            setColumnWidth(Math.floor(sizes.width / 6));
          }
        };
        // Updating the variable on window resize
        useEffect(() => {
          function handleResize() {
            getWidth();
          }
          window.addEventListener("resize", handleResize);
          return (_) => {
            window.removeEventListener("resize", handleResize);
          };
        });
    

    I was wondering if such a feature can be implemented natively? or if I'm missing a straightforward way to do this. I'm still a little new to react, so any help would be appreciated. Thanks a lot for this layout it works great in everything else.

    What would be awesome is if the number of columns for certain breakpoints could be set in the XMasonry component itself and have the column width be automatically calculated. Something like this <XMasonry columns={{ 480: 2, 768: 3, 1280: 4, 1536: 6 }}>

    opened by tejasahluwalia 11
  • Error in ./components/XBlock.jsx

    Error in ./components/XBlock.jsx

    Good Day. I noticed that many others in the past solve issues by importing the dist/index.js, but as you've pointed out, it bloats the package size as well as potentially not having a complete map?

    Full error:

     `
     ModuleParseError: Module parse failed: Unexpected token (13:24) You may need an appropriate loader to handle this file type.
    
     // };    
     
     static defaultProps = {    
    
         width: 1,    
         measured: false    
    

    `

    When I import the full path import { XMasonry, XBlock } from 'react-xmasonry/dist/index.js' the error disappears.

    v 2.5.5

    opened by dmayo2 11
  • Issues with server side rendering.

    Issues with server side rendering.

    Hey there, We're trying this with this starter kit https://github.com/kriasoft/react-starter-kit. The issue that we're having is that we get an empty div when the client renders. If we disable Javascript, we get all the <XBlock> items. With Javascript enabled we see the first load on the server and then all content disappears. We wrapped the content in a div (display block) as you suggest in #2

    Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
     (client) <div class="xmasonry" style="position:re
     (server) <div class="xmasonry xmasonry-static" st
    

    Any ideas what could be the issue?

    Thanks!

    opened by ghost 10
  • Masonry not displayed on page load

    Masonry not displayed on page load

    Hi,

    I've integrated this masonry into my Ionic React project. On the page load, cards are not displayed. When I adjust the page screen size, it will appear. I don't know what the was issue.

    When I check the DOM it was empty.

    <div class="xmasonry" style="position: relative; height: 0px;"></div>

    I love this feature after resize, by default it didn't load. 😞

    opened by aruljayaraj 9
  • Can't get number of columns on resize

    Can't get number of columns on resize

    Hey ZitRos. Thanks for providing this wonderful thing. I'm using this in my electron + react project :)

    I'm trying to get the number of columns with this.xMasonry.columns. It works great on load. But I'm having trouble trying to get the number when user resized the window as there's no callback method on resize. Is there a way to retrieve the number when the column count changed?

    opened by gaddafirusli 9
  • The XMasonry grid does not render children when testing with enzyme

    The XMasonry grid does not render children when testing with enzyme

    Reproduction:

    import React from 'react';
    import { mount } from 'enzyme';
    import { XMasonry, XBlock } from 'react-xmasonry';
    
    describe('Grid', () => {
    
      it('Render the <XBlock /> child components', () => {
        const masonry = mount(<XMasonry>
          <XBlock key={1}>
            <div> hello </div>
          </XBlock>
          <XBlock key={2}>
            <div> grid </div>
          </XBlock>
        </XMasonry>);
    
        console.log(masonry.debug());
    
        expect(masonry.children().length).toEqual(2);
      });
    
    });
    
    

    The output (I run the tests with jest):

     FAIL  tests/Grid.test.js
      Grid
        ✕ Render the <XBlock /> child components (5ms)
    
      ● Grid › Render the <XBlock /> child components
    
        expect(received).toEqual(expected)
    
        Expected value to equal:
          2
        Received:
          1
    
          at Object.<anonymous> (tests/Grid.test.js:63:39)
              at new Promise (<anonymous>)
              at <anonymous>
          at process._tickCallback (internal/process/next_tick.js:188:7)
    
      console.log tests/Grid.test.js:61
        <t center={true} maxColumns={Infinity} responsive={true} smartUpdate={true} smartUpdateCeil={Infinity} targetBlockWidth={300} updateOnFontLoad={true} updateOnImagesLoad={true}>
          <div className="xmasonry" style={{...}} />
        </t>
    Test Suites: 1 failed, 1 total
    Tests:       1 failed, 1 total
    Snapshots:   0 total
    Time:        0.365s, estimated 1s
    

    As you can see I am also trying to log the rendered tree to the console, but it looks like this:

    <t center={true} maxColumns={Infinity} responsive={true} smartUpdate={true} smartUpdateCeil={Infinity} targetBlockWidth={300} updateOnFontLoad={true} updateOnImagesLoad={true}>
        <div className="xmasonry" style={{...}} />
    </t>
    

    and does not render the <XBlock> components or the children

    awaits feedback 
    opened by michalczaplinski 8
  •  Cannot read property 'displayName' of undefined

    Cannot read property 'displayName' of undefined

    Hello @ZitRos , I'm getting an error when mixing an XBlock to a map of XBlocks.

    Here is simple code to reproduce the issue:

    render() {
        const data = [1, 2, 3, 4, 5];
        return (
          <XMasonry>
            <XBlock key={0}>
              <div className="card">
                <h1>Card #{0}</h1>
                <p>Any text!</p>
              </div>
            </XBlock>
            {data.map(number =>
              <XBlock key={number}>
                <div className="card">
                  <h1>Card #{number}</h1>
                  <p>Any text!</p>
                </div>
              </XBlock>
            )}
          </XMasonry>
        );
      }
    }
    

    This will produce the following error in the console:

     Uncaught TypeError: Cannot read property 'displayName' of undefined
        at getDisplayName (modules.js?hash=d3a0317…:3230)
        at Object.getCurrentStackAddendum (modules.js?hash=d3a0317…:3340)
        at validateExplicitKey (modules.js?hash=d3a0317…:2918)
        at validateChildKeys (modules.js?hash=d3a0317…:2938)
        at Object.createElement (modules.js?hash=d3a0317…:3026)
        at XMasonry.render (XMasonry.jsx:385)
        at modules.js?hash=d3a0317…:18044
        at measureLifeCyclePerf (modules.js?hash=d3a0317…:17323)
        at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (modules.js?hash=d3a0317…:18043)
        at ReactCompositeComponentWrapper._renderValidatedComponent (modules.js?hash=d3a0317…:18070)  
    

    Any idea what might be causing this?

    bug 
    opened by aogaili 7
  • Set minimum size of XBlock

    Set minimum size of XBlock

    I can't find a way to set the minimum size of the content of an XBlock.

    Trying to use min-width on either the XBlock, its direct child, or any nested children results in the XBlocks overlapping.

    image

    Is there any easy way to implement a minimum width for an XBlock?

    opened by davwheat 6
  • Please include ref props types for Typescript

    Please include ref props types for Typescript

    Hi,

    Thank you for this wonderful tool. Could you please add props of ref of xMasonry component in the type file definition. Will it be possible to add gaps for this component?

    opened by hjpunzalan 4
Owner
Nikita Savchenko
Full-stack, JavaScript, Blockchain developer and a creative man who enjoys what he does.
Nikita Savchenko
React-layout - Layout component for React. Handling the overall layout of a page

Layout Handling the overall layout of a page. ⚠️ Note: Implemented with flex lay

uiw 2 Jul 10, 2022
React-Grid-Layout is a grid layout system much like Packery or Gridster, for React.

A draggable and resizable grid layout with responsive breakpoints, for React.

RGL 16.9k Jan 2, 2023
Layout-reactJS - Layout with React JS using NASA API

Layout with React JS using NASA API Website link on the web: Click Here Preview:

Anastacio Menezes 4 Feb 2, 2022
A React.js component for using @desandro's Masonry

React Masonry Component IE8 support if you wish to have IE8 support, v2 with React 0.14 is the highest version available. Table of contents Usage Basi

Eirik L. Vullum 1.4k Dec 19, 2022
The Masonry List implementation which looks like the `FlatList` in React Native

react-native-masonry-list Pinterest like listview made in React Native. It just behaves like the FlatList so it is easy to use. Installation yarn add

Hyo 258 Dec 30, 2022
🧱 High-performance masonry layouts for React

?? masonic npm i masonic A performant and versatile virtualized masonry grid for React based on Brian Vaughn's react-virtualized and further inspired

Jared Lunde 451 Dec 29, 2022
Customizable masonry Flatlist. it just behave like Flatlist but using ScrollView behind the scene

Would you like to support me? react-native-masonry-grid Customizable masonry Flatlist. it just behave like Flatlist but using ScrollView behind the sc

Numan 5 Sep 7, 2022
Auto Responsive Layout Library For React

autoresponsive-react Auto responsive grid layout library for React. Who are using ⭐ ⭐ ⭐ alibaba/ice ⭐ ⭐ ⭐ ice-lab/react-materials ⭐ ⭐ ⭐ ant-design/ant

达峰的夏天 1.5k Dec 15, 2022
The layout engine for React

Responsive, sortable, filterable and draggable grid layouts with React Design Principles ????‍?? Muuri-React is the React implementation of the amazin

Paolo Longo 274 Dec 21, 2022
A draggable and resizable grid layout with responsive breakpoints, for React.

React-Grid-Layout React-Grid-Layout is a grid layout system much like Packery or Gridster, for React. Unlike those systems, it is responsive and suppo

Samuel Reed 16.9k Jan 1, 2023
Resizable Flex layout container components for advanced React web applications

About Re-F|ex Re-F|ex is a React flex-based layout component library which I created because none of the components I found out there could satisfy my

Philippe Leefsma 532 Jan 8, 2023
Animated grid layout component for React

react-stonecutter Animated grid layout component for React, inspired by Masonry. Choose between CSS Transitions or React-Motion for animation. Demo In

Dan Train 1.2k Dec 24, 2022
FlexLayout is a layout manager that arranges React components in multiple tab sets, tabs can be resized and moved.

FlexLayout is a layout manager that arranges React components in multiple tab sets, tabs can be resized and moved.

Caplin 649 Jan 7, 2023
Resizable Flex layout container components for advanced React web applications

About Re-F|ex Re-F|ex is a React flex-based layout component library which I created because none of the components I found out there could satisfy my

Philippe Leefsma 530 Dec 21, 2022
Photo layout editor for react

react-photo-layout-editor 사진 레이아웃을 편집하는 웹 프로그램입니다. This is photo layout editor for react 예전 Instagram blog( http://blog.instagram.com/ )에 있는 정렬된 이미지의

redgoose 115 Oct 7, 2022
This react component resize the layout of HTML using a handle

react-resize-layout This react component resize the layout of HTML using a handle Demo View the demo page Example View the example demo page npm insta

null 36 Nov 3, 2022
Physical representation of layout composition to create declarative responsive layouts in React.

Atomic Layout is a spatial distribution library for React. It uses CSS Grid to define layout areas and render them as React components. This pattern e

Artem Zakharchenko 1.1k Dec 26, 2022
A powerful React component to abstract over flexbox and create any layout on any browser

FlexView A powerful React component to abstract over flexbox and create any layout on any browser. Install yarn add react-flexview Why The flexbox AP

buildo 277 Nov 11, 2022
Kilvin is a set of universal & primitive Layout Components for React.

Kilvin is a set of universal & primitive Layout Components for React.

Robin Weser 21 May 26, 2022