React-Grid-Layout v2 made width required and pushed data-grid behind the legacy entry point
A draggable and resizable grid layout with responsive breakpoints, for React.
At a glance
- What is it?
- React-Grid-Layout is a draggable and resizable grid system for React, now rewritten in TypeScript with breakpoint layouts and pluggable compaction. Version 2 is a different contract from version 1: width is mandatory, callbacks are read-only, compaction is a strategy object, and the fast algorithm sits in a separate entry point.
- Who is it for?
- Take the v2 API for anything new, including server rendering through measureBeforeMount, and take react-grid-layout/legacy only when a v1 codebase cannot be reworked this quarter. Before you copy a snippet, check the tag it came from, because 1.5.4 and 2.2.4 were both published on 2026-07-29 and the two lines do not share prop names.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- react-grid-layout/react-grid-layout22,492 ★ · +128
| Repository | 2026-07-29 | 2026-11-14 |
|---|---|---|
| react-grid-layout/react-grid-layout | 22.4k | 22.5k |
128 Stars in the last 108 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The width prop became required, so nothing renders until you measure the container
v1 handed the grid a width and got on with it. v2 makes width a required prop, and the replacement the project offers is a hook. useContainerWidth returns three things, width, containerRef and mounted, and the migration example gates the entire grid behind mounted so that children are not rendered on the first pass. That flag is not decoration. Until it flips you have no width, and the grid has nothing to compute column positions from, so a naive port of an existing page shows an empty container for a frame.
For server rendering the answer is a prop instead, and the use case table sends SSR to v2 with measureBeforeMount: true. What the library cannot do is measure your DOM for you outside that hook. The consequence for the reader is that measurement responsibility moves up into your component, and any container sized by a percentage or an intrinsic parent needs its own check.
import ReactGridLayout, { useContainerWidth, verticalCompactor } from 'react-grid-layout';
function MyGrid() {
const { width, containerRef, mounted } = useContainerWidth();
return (
<div ref={containerRef}>
{mounted && (
<ReactGridLayout
width={width}
layout={layout}
gridConfig={{ cols: 12, rowHeight: 30 }}
dragConfig={{ enabled: true, handle: '.handle' }}
compactor={verticalCompactor}
>
{children}
</ReactGridLayout>
)}
</div>
);
}onDragStart now waits for three pixels, so a stationary press fires nothing
One breaking change reads that onDragStart now fires after 3px movement rather than on mousedown, and it names the substitute for immediate response: onMouseDown. That single threshold changes how an interface built on the old behaviour feels. A handler that opened a panel, started a rename or selected an item on press does nothing when the pointer never moves, so a control that used to answer the click now looks dead. The other direction matters too: a deliberate one or two pixel nudge no longer counts as a drag start at all, so precision gestures inside a cell need a handler of their own.
What the library cannot do is hand you both behaviours from one prop. You wire onDragStart or onMouseDown and decide where the threshold belongs in your own event layer. The consequence for a reader is that demos copied from older tutorials keep the old assumption, and the symptom arrives as an unresponsive control rather than as a type error or a build failure, which makes it slow to trace back to a version change.
Callback parameters are read-only, so adjusting an item in place stops moving it
The breaking change table states that callback parameters are read-only and names the alternative: use onLayoutChange or constraints instead of mutation. The old pattern of catching an item inside a drag or resize callback and writing a new size or position back into it has no effect now, because the object handed to you is not the layout the grid will render.
What the library cannot offer is a compatibility path for code that wrote back into the callback argument, and the documented substitutes are only the two named ones. For a reader the consequence is concrete: a dashboard that used to clamp an item to a maximum height inside its own callback now lets it exceed that limit, and the clamp has to be expressed as a constraint in the configuration objects or applied in onLayoutChange before the state you persist.
data-grid and the RGL.Layout type names survive only behind react-grid-layout/legacy
v2 requires an explicit layout prop, and the breaking change table marks data-grid as available in the legacy wrapper only. That is the most disruptive line for anyone migrating a template where each child carried its own position attributes. The quick migration is a one line import change, and the claim made for that wrapper is 100% runtime API compatibility with v1:
- import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout';
+ import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout/legacy';The TypeScript story is less forgiving than the runtime story. If you were on @types/react-grid-layout, v2 ships its own types but renames the central ones: RGL.Layout becomes LayoutItem for a single grid item, RGL.Layout[] becomes Layout for the array, and RGL.Layouts becomes ResponsiveLayouts for the breakpoint map. The wrapper saves your runtime code and still costs a pass over your type annotations. What it cannot do is let the two worlds share a name.
Compaction became a strategy object, and the O(n log n) algorithm sits behind /extras
Compaction no longer has a boolean switch. It is a Compactor interface you pass in, with vertical, horizontal and custom algorithms named in the v2 feature list, and the breaking changes table places the optional fast O(n log n) algorithm in /extras rather than in the default entry point. Removing verticalCompact belongs to the same move: turning compaction off now means compactType={null} or compactor={noCompactor}.
What this cannot do is give you the algorithm and the off switch from the same import. A bundle that wants the O(n log n) path pulls a second subpath, and the exported noCompactor name becomes the way to express a layout where items keep the gaps you gave them. For a reader the consequence is that a dashboard relying on the old boolean has to be rewritten at the configuration boundary rather than at the prop.
The UMD build is gone, and the example pages are generated behind a CONTENT_BASE flag
One row of the breaking changes table reads UMD bundle removed, with the replacement given as a bundler: Vite, webpack or esbuild. That deletes the script tag path for anyone serving this grid from a page with no build step, and the package manifest offers no UMD file to fall back on.
The demo pages are generated rather than committed. The Makefile target for viewing examples runs `env CONTENT_BASE="/react-grid-layout/examples/" node ./examples/util/generate.js` and then serves with webpack, and the target that builds the published pages runs the same script after a webpack pass. What the repository cannot do for you is guess that base path.
Two release lines shipped on the same day while the default branch is master
The release list holds 2.3.0 from 2026-10-05, v2.2.4 published 2026-07-29 at 14:49, and 1.5.4 published 2026-07-29 at 01:43. Within about thirteen hours the project published the current TypeScript line and a 1.x line, which reads as the older API still receiving fixes rather than as a mistake. The repository is not archived and its last push is 2026-11-02.
What the release list cannot tell you is which line an unpinned install resolves to, and the two lines disagree about names: hooks and the required width prop exist on one side only, and the type renames land the other way. A lockfile written before the 2.x work keeps a 1.x tree alive with no visible warning. For a reader the consequence is that the tag prefix is the piece of information worth checking before pasting a snippet, and omitting the version from your own package.json turns that choice into one you are not making on purpose.
The exports map publishes five subpaths and marks only CSS as a side effect
The package manifest for 2.3.0 lists an exports map with the root entry plus ./core, ./react, ./legacy, ./extras and ./css/styles.css, each with its own import and require type declarations, and the dual dist/index.mjs and dist/index.js entries are what the tree-shakeable ESM and CJS build claim rests on. The v2 feature list names four entry points and does not list ./react. The files array ships dist, css, index.js and index-dev.js, while the repository root also holds index.js.flow, which is not in that list.
What the package cannot do is hand a Flow consumer the declarations sitting in the repository, or accept a side effect beyond CSS: sideEffects lists only *.css, so a bundler is free to drop other imports it considers free of side effects. The consequence is that a Flow project still has to source its own type declarations for this grid, and an extension that works by importing purely for effect can vanish from a production build without a build error to chase.
Editorial conclusion
Take the v2 API for anything new, including server rendering through measureBeforeMount, and take react-grid-layout/legacy only when a v1 codebase cannot be reworked this quarter. Before you copy a snippet, check the tag it came from, because 1.5.4 and 2.2.4 were both published on 2026-07-29 and the two lines do not share prop names. Also decide where your item constraints live, since read-only callback parameters rule out the in place adjustments that many older dashboards used.
Frequently asked questions
What is React grid layout?
React-Grid-Layout is a draggable and resizable grid layout system for React, in the mould of Packery and Gridster, and the difference it claims over those two is responsiveness with breakpoints. Breakpoint layouts can be supplied by the user or autogenerated, it is React-only, and it does not require jQuery.
how to use react grid layout
Import the root entry, measure your container with useContainerWidth, and gate rendering on the mounted flag it returns. Configuration is grouped into gridConfig for cols, rowHeight, margin and padding, dragConfig for the handle and cancel selectors, resizeConfig for handles, plus a positionStrategy and a compactor. In v2 the layout is passed as an explicit prop and children no longer read data-grid.
install react grid layout
The published package is react-grid-layout at version 2.3.0, with its main entry at dist/index.js, an ESM module at dist/index.mjs and type declarations at dist/index.d.ts, and a separate css/styles.css file. Since v2 the types ship with the package, so a separate @types/react-grid-layout install is no longer needed.
react grid layout vs gridstack
The README states that it resembles Packery and Gridster, is responsive with breakpoints where layouts come from the user or are autogenerated, is React-only, and does not require jQuery.
react grid layout vertical and horizontal compact
Compaction is pluggable through the Compactor interface, and the feature list names vertical, horizontal and custom algorithms. The verticalCompact prop was removed in v2, so compaction is turned off with compactType={null} or compactor={noCompactor}, and an optional fast O(n log n) algorithm is imported from the /extras entry point.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/react-grid-layout-react-grid-layout)Star history chart for your README
[](https://hysenlabs.com/projects/react-grid-layout-react-grid-layout)Was this useful?