react-grid-layout 1.5.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +1075 -432
  2. package/css/styles.css +6 -4
  3. package/dist/ResponsiveGridLayout-CH4s0tKj.d.ts +124 -0
  4. package/dist/ResponsiveGridLayout-D6lFRE3f.d.mts +124 -0
  5. package/dist/calculate-CwYDW8na.d.mts +168 -0
  6. package/dist/calculate-mgLpNJ5O.d.ts +168 -0
  7. package/dist/chunk-2KUHNJXF.mjs +90 -0
  8. package/dist/chunk-2KUHNJXF.mjs.map +1 -0
  9. package/dist/chunk-3WO4SAYB.js +868 -0
  10. package/dist/chunk-3WO4SAYB.js.map +1 -0
  11. package/dist/chunk-4HNUMWQK.mjs +822 -0
  12. package/dist/chunk-4HNUMWQK.mjs.map +1 -0
  13. package/dist/chunk-BFTKGAP3.js +1309 -0
  14. package/dist/chunk-BFTKGAP3.js.map +1 -0
  15. package/dist/chunk-F6NQPYKT.js +98 -0
  16. package/dist/chunk-F6NQPYKT.js.map +1 -0
  17. package/dist/chunk-H5KMDLY3.js +434 -0
  18. package/dist/chunk-H5KMDLY3.js.map +1 -0
  19. package/dist/chunk-PBQSHIID.js +4 -0
  20. package/dist/chunk-PBQSHIID.js.map +1 -0
  21. package/dist/chunk-R35HZZTA.mjs +1300 -0
  22. package/dist/chunk-R35HZZTA.mjs.map +1 -0
  23. package/dist/chunk-ZCXE6SR5.mjs +428 -0
  24. package/dist/chunk-ZCXE6SR5.mjs.map +1 -0
  25. package/dist/chunk-ZWN22PS2.mjs +3 -0
  26. package/dist/chunk-ZWN22PS2.mjs.map +1 -0
  27. package/dist/core.d.mts +33 -0
  28. package/dist/core.d.ts +33 -0
  29. package/dist/core.js +218 -0
  30. package/dist/core.js.map +1 -0
  31. package/dist/core.mjs +5 -0
  32. package/dist/core.mjs.map +1 -0
  33. package/dist/extras.d.mts +78 -0
  34. package/dist/extras.d.ts +78 -0
  35. package/dist/extras.js +91 -0
  36. package/dist/extras.js.map +1 -0
  37. package/dist/extras.mjs +89 -0
  38. package/dist/extras.mjs.map +1 -0
  39. package/dist/index.d.mts +7 -0
  40. package/dist/index.d.ts +7 -0
  41. package/dist/index.js +154 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/index.mjs +7 -0
  44. package/dist/index.mjs.map +1 -0
  45. package/dist/legacy.d.mts +163 -0
  46. package/dist/legacy.d.ts +163 -0
  47. package/dist/legacy.js +319 -0
  48. package/dist/legacy.js.map +1 -0
  49. package/dist/legacy.mjs +307 -0
  50. package/dist/legacy.mjs.map +1 -0
  51. package/dist/position-BmN1z36J.d.mts +319 -0
  52. package/dist/position-Dk2b4ZMS.d.ts +319 -0
  53. package/dist/react.d.mts +351 -0
  54. package/dist/react.d.ts +351 -0
  55. package/dist/react.js +96 -0
  56. package/dist/react.js.map +1 -0
  57. package/dist/react.mjs +7 -0
  58. package/dist/react.mjs.map +1 -0
  59. package/dist/responsive-C4L1ESlm.d.ts +145 -0
  60. package/dist/responsive-CJxefsYw.d.mts +145 -0
  61. package/dist/types-Cxf4nHNr.d.mts +375 -0
  62. package/dist/types-Cxf4nHNr.d.ts +375 -0
  63. package/index-dev.js +8 -0
  64. package/package.json +132 -39
  65. package/.babelrc.js +0 -22
  66. package/.browserslistrc +0 -3
  67. package/.eslintignore +0 -4
  68. package/.flowconfig +0 -20
  69. package/.prettierignore +0 -4
  70. package/.prettierrc +0 -17
  71. package/CHANGELOG.md +0 -985
  72. package/build/GridItem.js +0 -640
  73. package/build/ReactGridLayout.js +0 -744
  74. package/build/ReactGridLayoutPropTypes.js +0 -210
  75. package/build/ResponsiveReactGridLayout.js +0 -294
  76. package/build/calculateUtils.js +0 -165
  77. package/build/components/WidthProvider.js +0 -111
  78. package/build/fastRGLPropsEqual.js +0 -5
  79. package/build/responsiveUtils.js +0 -101
  80. package/build/utils.js +0 -834
  81. package/dist/react-grid-layout.min.js +0 -2
  82. package/dist/react-grid-layout.min.js.map +0 -1
  83. package/index.js.flow +0 -8
  84. package/ip_fetcher +0 -0
  85. package/ip_fetcher.c +0 -47
  86. package/lib/GridItem.jsx +0 -689
  87. package/lib/ReactGridLayout.jsx +0 -855
  88. package/lib/ReactGridLayoutPropTypes.js +0 -241
  89. package/lib/ResponsiveReactGridLayout.jsx +0 -349
  90. package/lib/calculateUtils.js +0 -169
  91. package/lib/components/WidthProvider.jsx +0 -110
  92. package/lib/fastRGLPropsEqual.js +0 -46
  93. package/lib/responsiveUtils.js +0 -118
  94. package/lib/utils.js +0 -979
package/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # React-Grid-Layout
2
2
 
3
- [![travis build](https://travis-ci.org/STRML/react-grid-layout.svg?branch=master)](https://travis-ci.org/STRML/react-grid-layout)
4
- [![CDNJS](https://img.shields.io/cdnjs/v/react-grid-layout.svg)](https://cdnjs.com/libraries/react-grid-layout)
5
3
  [![npm package](https://img.shields.io/npm/v/react-grid-layout.svg?style=flat-square)](https://www.npmjs.org/package/react-grid-layout)
6
4
  [![npm downloads](https://img.shields.io/npm/dt/react-grid-layout.svg?maxAge=2592000)]()
7
5
 
@@ -21,19 +19,97 @@ RGL is React-only and does not require jQuery.
21
19
 
22
20
  ## Table of Contents
23
21
 
22
+ - [What's New in v2](#whats-new-in-v2)
23
+ - [Migrating from v1](#migrating-from-v1)
24
24
  - [Demos](#demos)
25
25
  - [Features](#features)
26
26
  - [Installation](#installation)
27
- - [Usage](#usage)
27
+ - [Quick Start](#quick-start)
28
28
  - [Responsive Usage](#responsive-usage)
29
29
  - [Providing Grid Width](#providing-grid-width)
30
- - [Grid Layout Props](#grid-layout-props)
31
- - [Responsive Grid Layout Props](#responsive-grid-layout-props)
32
- - [Grid Item Props](#grid-item-props)
33
- - [User Recipes](../../wiki/Users-recipes)
30
+ - [Hooks API](#hooks-api)
31
+ - [API Reference](#api-reference)
32
+ - [Extending: Custom Compactors & Position Strategies](#extending-custom-compactors--position-strategies)
33
+ - [Extras](#extras)
34
34
  - [Performance](#performance)
35
35
  - [Contribute](#contribute)
36
- - [TODO List](#todo-list)
36
+
37
+ ## What's New in v2
38
+
39
+ Version 2 is a complete TypeScript rewrite with a modernized API:
40
+
41
+ - **Full TypeScript support** - First-class types, no more `@types/react-grid-layout`
42
+ - **React Hooks** - New `useContainerWidth`, `useGridLayout`, and `useResponsiveLayout` hooks
43
+ - **Composable Configuration** - Group related props into focused interfaces:
44
+ - `gridConfig` - cols, rowHeight, margin, padding
45
+ - `dragConfig` - enable, handle, cancel, bounded
46
+ - `resizeConfig` - enable, handles
47
+ - `positionStrategy` - transform vs absolute positioning
48
+ - `compactor` - vertical, horizontal, or custom algorithms
49
+ - **Modular architecture** - Import only what you need:
50
+ - `react-grid-layout` - React components and hooks (v2 API)
51
+ - `react-grid-layout/core` - Pure layout algorithms (framework-agnostic)
52
+ - `react-grid-layout/legacy` - v1 flat props API for migration
53
+ - `react-grid-layout/extras` - Optional components like `GridBackground`
54
+ - **Smaller bundle** - Tree-shakeable ESM and CJS builds
55
+
56
+ ### Breaking Changes
57
+
58
+ See the [RFC](./rfcs/0001-v2-typescript-rewrite.md#breaking-changes-in-v2) for detailed migration examples.
59
+
60
+ | Change | Description |
61
+ | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
62
+ | [`width` prop required](./rfcs/0001-v2-typescript-rewrite.md#breaking-changes-in-v2) | Use `useContainerWidth` hook or provide your own measurement |
63
+ | [`onDragStart` threshold](./rfcs/0001-v2-typescript-rewrite.md#1-ondragstart-no-longer-fires-on-click-only-events) | Now fires after 3px movement, not on mousedown. Use `onMouseDown` for immediate response |
64
+ | [Immutable callbacks](./rfcs/0001-v2-typescript-rewrite.md#2-immutable-callback-parameters) | Callback parameters are read-only. Use `onLayoutChange` or constraints instead of mutation |
65
+ | [`data-grid` in legacy only](./rfcs/0001-v2-typescript-rewrite.md#3-data-grid-prop-only-available-in-legacy-wrapper) | v2 requires explicit `layout` prop. Use legacy wrapper for `data-grid` |
66
+ | [Fast compaction](./rfcs/0001-v2-typescript-rewrite.md#4-fast-compaction-algorithm-by-default) | O(n log n) algorithm may differ in edge cases. Use `compact()` from `/core` for exact v1 behavior |
67
+ | UMD bundle removed | Use a bundler (Vite, webpack, esbuild) |
68
+ | `verticalCompact` removed | Use `compactType={null}` or `compactor={noCompactor}` |
69
+
70
+ ## Migrating from v1
71
+
72
+ **Quick migration** - change your import to use the legacy wrapper:
73
+
74
+ ```diff
75
+ - import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout';
76
+ + import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout/legacy';
77
+ ```
78
+
79
+ This provides **100% API compatibility** with v1.
80
+
81
+ **Full migration** - adopt the v2 API for new features and better tree-shaking:
82
+
83
+ ```typescript
84
+ import ReactGridLayout, { useContainerWidth, verticalCompactor } from 'react-grid-layout';
85
+
86
+ function MyGrid() {
87
+ const { width, containerRef, mounted } = useContainerWidth();
88
+
89
+ return (
90
+ <div ref={containerRef}>
91
+ {mounted && (
92
+ <ReactGridLayout
93
+ width={width}
94
+ layout={layout}
95
+ gridConfig={{ cols: 12, rowHeight: 30 }}
96
+ dragConfig={{ enabled: true, handle: '.handle' }}
97
+ compactor={verticalCompactor}
98
+ >
99
+ {children}
100
+ </ReactGridLayout>
101
+ )}
102
+ </div>
103
+ );
104
+ }
105
+ ```
106
+
107
+ | Use Case | Recommendation |
108
+ | -------------------- | ---------------------------------- |
109
+ | Existing v1 codebase | `react-grid-layout/legacy` |
110
+ | New project | v2 API with hooks |
111
+ | Custom compaction | v2 with custom `Compactor` |
112
+ | SSR | v2 with `measureBeforeMount: true` |
37
113
 
38
114
  ## Demos
39
115
 
@@ -62,30 +138,21 @@ RGL is React-only and does not require jQuery.
62
138
 
63
139
  #### Projects Using React-Grid-Layout
64
140
 
141
+ - [Basedash](https://www.basedash.com)
65
142
  - [BitMEX](https://www.bitmex.com/)
66
143
  - [AWS CloudFront Dashboards](https://aws.amazon.com/blogs/aws/cloudwatch-dashboards-create-use-customized-metrics-views/)
67
144
  - [Grafana](https://grafana.com/)
68
145
  - [Metabase](http://www.metabase.com/)
69
146
  - [HubSpot](http://www.hubspot.com)
70
- - [ComNetViz](http://www.grotto-networking.com/ComNetViz/ComNetViz.html)
71
- - [Stoplight](https://app.stoplight.io)
72
- - [Reflect](https://reflect.io)
73
- - [ez-Dashing](https://github.com/ylacaute/ez-Dashing)
74
147
  - [Kibana](https://www.elastic.co/products/kibana)
75
- - [Graphext](https://graphext.com/)
76
148
  - [Monday](https://support.monday.com/hc/en-us/articles/360002187819-What-are-the-Dashboards-)
77
- - [Quadency](https://quadency.com/)
78
- - [Hakkiri](https://www.hakkiri.io)
79
- - [Ubidots](https://help.ubidots.com/en/articles/2400308-create-dashboards-and-widgets)
80
- - [Statsout](https://statsout.com/)
81
- - [Datto RMM](https://www.datto.com/uk/products/rmm/)
82
- - [SquaredUp](https://squaredup.com/)
83
149
 
84
150
  _Know of others? Create a PR to let me know!_
85
151
 
86
152
  ## Features
87
153
 
88
154
  - 100% React - no jQuery
155
+ - Full TypeScript support
89
156
  - Compatible with server-rendered apps
90
157
  - Draggable widgets
91
158
  - Resizable widgets
@@ -97,506 +164,1098 @@ _Know of others? Create a PR to let me know!_
97
164
  - Responsive breakpoints
98
165
  - Separate layouts per responsive breakpoint
99
166
  - Grid Items placed using CSS Transforms
100
- - Performance with CSS Transforms: [on](http://i.imgur.com/FTogpLp.jpg) / [off](http://i.imgur.com/gOveMm8.jpg), note paint (green) as % of time
101
167
  - Compatibility with `<React.StrictMode>`
102
168
 
103
- | Version | Compatibility |
104
- | ------------ | --------------- |
105
- | >= 0.17.0 | React 16 & 17 |
106
- | >= 0.11.3 | React 0.14 & 15 |
107
- | >= 0.10.0 | React 0.14 |
108
- | 0.8. - 0.9.2 | React 0.13 |
109
- | < 0.8 | React 0.12 |
169
+ | Version | Compatibility |
170
+ | --------- | --------------------- |
171
+ | >= 2.0.0 | React 18+, TypeScript |
172
+ | >= 0.17.0 | React 16 & 17 |
110
173
 
111
174
  ## Installation
112
175
 
113
- Install the React-Grid-Layout [package](https://www.npmjs.org/package/react-grid-layout) using [npm](https://www.npmjs.com/):
114
-
115
176
  ```bash
116
177
  npm install react-grid-layout
117
178
  ```
118
179
 
119
- Include the following stylesheets in your application:
180
+ Include the stylesheets in your application:
120
181
 
182
+ ```js
183
+ import "react-grid-layout/css/styles.css";
184
+ import "react-resizable/css/styles.css";
121
185
  ```
122
- /node_modules/react-grid-layout/css/styles.css
123
- /node_modules/react-resizable/css/styles.css
186
+
187
+ Or link them directly:
188
+
189
+ ```html
190
+ <link rel="stylesheet" href="/node_modules/react-grid-layout/css/styles.css" />
191
+ <link rel="stylesheet" href="/node_modules/react-resizable/css/styles.css" />
124
192
  ```
125
193
 
126
- ## Usage
194
+ ## Quick Start
127
195
 
128
- Use ReactGridLayout like any other component. The following example below will
129
- produce a grid with three items where:
196
+ ```tsx
197
+ import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
198
+ import "react-grid-layout/css/styles.css";
199
+ import "react-resizable/css/styles.css";
130
200
 
131
- - users will not be able to drag or resize item `a`
132
- - item `b` will be restricted to a minimum width of 2 grid blocks and a maximum width of 4 grid blocks
133
- - users will be able to freely drag and resize item `c`
201
+ function MyGrid() {
202
+ const { width, containerRef, mounted } = useContainerWidth();
134
203
 
135
- ```js
136
- import GridLayout from "react-grid-layout";
137
-
138
- class MyFirstGrid extends React.Component {
139
- render() {
140
- // layout is an array of objects, see the demo for more complete usage
141
- const layout = [
142
- { i: "a", x: 0, y: 0, w: 1, h: 2, static: true },
143
- { i: "b", x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 },
144
- { i: "c", x: 4, y: 0, w: 1, h: 2 }
145
- ];
146
- return (
147
- <GridLayout
148
- className="layout"
149
- layout={layout}
150
- cols={12}
151
- rowHeight={30}
152
- width={1200}
153
- >
154
- <div key="a">a</div>
155
- <div key="b">b</div>
156
- <div key="c">c</div>
157
- </GridLayout>
158
- );
159
- }
204
+ const layout = [
205
+ { i: "a", x: 0, y: 0, w: 1, h: 2, static: true },
206
+ { i: "b", x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 },
207
+ { i: "c", x: 4, y: 0, w: 1, h: 2 }
208
+ ];
209
+
210
+ return (
211
+ <div ref={containerRef}>
212
+ {mounted && (
213
+ <ReactGridLayout
214
+ layout={layout}
215
+ width={width}
216
+ gridConfig={{ cols: 12, rowHeight: 30 }}
217
+ >
218
+ <div key="a">a</div>
219
+ <div key="b">b</div>
220
+ <div key="c">c</div>
221
+ </ReactGridLayout>
222
+ )}
223
+ </div>
224
+ );
160
225
  }
161
226
  ```
162
227
 
163
- You may also choose to set layout properties directly on the children:
228
+ You can also define layout on children using `data-grid`:
229
+
230
+ ```tsx
231
+ <ReactGridLayout width={width} gridConfig={{ cols: 12, rowHeight: 30 }}>
232
+ <div key="a" data-grid={{ x: 0, y: 0, w: 1, h: 2, static: true }}>
233
+ a
234
+ </div>
235
+ <div key="b" data-grid={{ x: 1, y: 0, w: 3, h: 2 }}>
236
+ b
237
+ </div>
238
+ <div key="c" data-grid={{ x: 4, y: 0, w: 1, h: 2 }}>
239
+ c
240
+ </div>
241
+ </ReactGridLayout>
242
+ ```
164
243
 
165
- ```js
166
- import GridLayout from "react-grid-layout";
244
+ ## Responsive Usage
167
245
 
168
- class MyFirstGrid extends React.Component {
169
- render() {
170
- return (
171
- <GridLayout className="layout" cols={12} rowHeight={30} width={1200}>
172
- <div key="a" data-grid={{ x: 0, y: 0, w: 1, h: 2, static: true }}>
173
- a
174
- </div>
175
- <div key="b" data-grid={{ x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 }}>
176
- b
177
- </div>
178
- <div key="c" data-grid={{ x: 4, y: 0, w: 1, h: 2 }}>
179
- c
180
- </div>
181
- </GridLayout>
182
- );
183
- }
246
+ Use `Responsive` for automatic breakpoint handling:
247
+
248
+ ```tsx
249
+ import { Responsive, useContainerWidth } from "react-grid-layout";
250
+
251
+ function MyResponsiveGrid() {
252
+ const { width, containerRef, mounted } = useContainerWidth();
253
+
254
+ const layouts = {
255
+ lg: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }],
256
+ md: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }]
257
+ };
258
+
259
+ return (
260
+ <div ref={containerRef}>
261
+ {mounted && (
262
+ <Responsive
263
+ layouts={layouts}
264
+ breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
265
+ cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
266
+ width={width}
267
+ >
268
+ <div key="1">1</div>
269
+ <div key="2">2</div>
270
+ <div key="3">3</div>
271
+ </Responsive>
272
+ )}
273
+ </div>
274
+ );
184
275
  }
185
276
  ```
186
277
 
187
- ### Usage without Browserify/Webpack
278
+ ## Providing Grid Width
188
279
 
189
- A module usable in a `<script>` tag is included [here](/dist/react-grid-layout.min.js). It uses a UMD shim and
190
- excludes `React`, so it must be otherwise available in your application, either via RequireJS or on `window.React`.
280
+ The `width` prop is required. You have several options:
191
281
 
192
- ### Responsive Usage
282
+ ### Option 1: useContainerWidth Hook (Recommended)
193
283
 
194
- To make RGL responsive, use the `<ResponsiveReactGridLayout>` element:
284
+ ```tsx
285
+ import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
195
286
 
196
- ```js
197
- import { Responsive as ResponsiveGridLayout } from "react-grid-layout";
287
+ function MyGrid() {
288
+ const { width, containerRef, mounted } = useContainerWidth();
198
289
 
199
- class MyResponsiveGrid extends React.Component {
200
- render() {
201
- // {lg: layout1, md: layout2, ...}
202
- const layouts = getLayoutsFromSomewhere();
203
- return (
204
- <ResponsiveGridLayout
205
- className="layout"
206
- layouts={layouts}
207
- breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
208
- cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
209
- >
210
- <div key="1">1</div>
211
- <div key="2">2</div>
212
- <div key="3">3</div>
213
- </ResponsiveGridLayout>
214
- );
215
- }
290
+ return (
291
+ <div ref={containerRef}>
292
+ {mounted && <ReactGridLayout width={width}>...</ReactGridLayout>}
293
+ </div>
294
+ );
216
295
  }
217
296
  ```
218
297
 
219
- When in responsive mode, you should supply at least one breakpoint via the `layouts` property.
298
+ ### Option 2: Fixed Width
220
299
 
221
- When using `layouts`, it is best to supply as many breakpoints as possible, especially the largest one.
222
- If the largest is provided, RGL will attempt to interpolate the rest.
300
+ ```tsx
301
+ <ReactGridLayout width={1200}>...</ReactGridLayout>
302
+ ```
223
303
 
224
- You will also need to provide a `width`, when using `<ResponsiveReactGridLayout>` it is suggested you use the HOC
225
- `WidthProvider` as per the instructions below.
304
+ ### Option 3: CSS Container Queries or ResizeObserver
226
305
 
227
- It is possible to supply default mappings via the `data-grid` property on individual
228
- items, so that they would be taken into account within layout interpolation.
306
+ Use any width measurement library like [react-sizeme](https://github.com/ctrlplusb/react-sizeme) or your own ResizeObserver implementation.
229
307
 
230
- ### Providing Grid Width
308
+ ### Option 4: Legacy WidthProvider HOC
231
309
 
232
- Both `<ResponsiveReactGridLayout>` and `<ReactGridLayout>` take `width` to calculate
233
- positions on drag events. In simple cases a HOC `WidthProvider` can be used to automatically determine
234
- width upon initialization and window resize events.
310
+ For backwards compatibility, you can still use `WidthProvider`:
235
311
 
236
- ```js
237
- import { Responsive, WidthProvider } from "react-grid-layout";
312
+ ```tsx
313
+ import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";
238
314
 
239
- const ResponsiveGridLayout = WidthProvider(Responsive);
315
+ const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
240
316
 
241
- class MyResponsiveGrid extends React.Component {
242
- render() {
243
- // {lg: layout1, md: layout2, ...}
244
- var layouts = getLayoutsFromSomewhere();
245
- return (
246
- <ResponsiveGridLayout
247
- className="layout"
248
- layouts={layouts}
249
- breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
250
- cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
251
- >
252
- <div key="1">1</div>
253
- <div key="2">2</div>
254
- <div key="3">3</div>
255
- </ResponsiveGridLayout>
256
- );
257
- }
317
+ function MyGrid() {
318
+ return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
258
319
  }
259
320
  ```
260
321
 
261
- This allows you to easily replace `WidthProvider` with your own Provider HOC if you need more sophisticated logic.
322
+ ## Hooks API
262
323
 
263
- `WidthProvider` accepts a single prop, `measureBeforeMount`. If `true`, `WidthProvider` will measure the
264
- container's width before mounting children. Use this if you'd like to completely eliminate any resizing animation
265
- on application/component mount.
324
+ The v2 API provides three hooks for different use cases. Choose based on your needs:
266
325
 
267
- Have a more complicated layout? `WidthProvider` [is very simple](/lib/components/WidthProvider.jsx) and only
268
- listens to window `'resize'` events. If you need more power and flexibility, try the
269
- [SizeMe React HOC](https://github.com/ctrlplusb/react-sizeme) as an alternative to WidthProvider.
326
+ | Hook | Use When |
327
+ | --------------------- | -------------------------------------------------------------------- |
328
+ | `useContainerWidth` | You need responsive width measurement (most common) |
329
+ | `useGridLayout` | You're building a custom grid component or need direct state control |
330
+ | `useResponsiveLayout` | You're building a custom responsive grid with breakpoint logic |
270
331
 
271
- ### Grid Layout Props
332
+ ### useContainerWidth
272
333
 
273
- RGL supports the following properties (see the source for the final word on this):
334
+ Observes container width using ResizeObserver and provides reactive width updates. This is the recommended way to provide width to the grid.
274
335
 
275
- ```js
276
- //
277
- // Basic props
278
- //
279
-
280
- // This allows setting the initial width on the server side.
281
- // This is required unless using the HOC <WidthProvider> or similar
282
- width: number,
283
-
284
- // If true, the container height swells and contracts to fit contents
285
- autoSize: ?boolean = true,
286
-
287
- // Number of columns in this layout.
288
- cols: ?number = 12,
289
-
290
- // A CSS selector for tags that will not be draggable.
291
- // For example: draggableCancel:'.MyNonDraggableAreaClassName'
292
- // If you forget the leading . it will not work.
293
- // .react-resizable-handle" is always prepended to this value.
294
- draggableCancel: ?string = '',
295
-
296
- // A CSS selector for tags that will act as the draggable handle.
297
- // For example: draggableHandle:'.MyDragHandleClassName'
298
- // If you forget the leading . it will not work.
299
- draggableHandle: ?string = '',
300
-
301
- // Compaction type.
302
- compactType: ?('vertical' | 'horizontal' | null) = 'vertical';
303
-
304
- // Layout is an array of objects with the format:
305
- // The index into the layout must match the key used on each item component.
306
- // If you choose to use custom keys, you can specify that key in the layout
307
- // array objects using the `i` prop.
308
- layout: ?Array<{i?: string, x: number, y: number, w: number, h: number}> = null, // If not provided, use data-grid props on children
309
-
310
- // Margin between items [x, y] in px.
311
- margin: ?[number, number] = [10, 10],
312
-
313
- // Padding inside the container [x, y] in px
314
- containerPadding: ?[number, number] = margin,
315
-
316
- // Rows have a static height, but you can change this based on breakpoints
317
- // if you like.
318
- rowHeight: ?number = 150,
319
-
320
- // Configuration of a dropping element. Dropping element is a "virtual" element
321
- // which appears when you drag over some element from outside.
322
- // It can be changed by passing specific parameters:
323
- // i - id of an element
324
- // w - width of an element
325
- // h - height of an element
326
- droppingItem?: { i: string, w: number, h: number }
327
-
328
- //
329
- // Flags
330
- //
331
- isDraggable: ?boolean = true,
332
- isResizable: ?boolean = true,
333
- isBounded: ?boolean = false,
334
- // Uses CSS3 translate() instead of position top/left.
335
- // This makes about 6x faster paint performance
336
- useCSSTransforms: ?boolean = true,
337
- // If parent DOM node of ResponsiveReactGridLayout or ReactGridLayout has "transform: scale(n)" css property,
338
- // we should set scale coefficient to avoid render artefacts while dragging.
339
- transformScale: ?number = 1,
340
-
341
- // If true, grid can be placed one over the other.
342
- // If set, implies `preventCollision`.
343
- allowOverlap: ?boolean = false,
344
-
345
- // If true, grid items won't change position when being
346
- // dragged over. If `allowOverlap` is still false,
347
- // this simply won't allow one to drop on an existing object.
348
- preventCollision: ?boolean = false,
349
-
350
- // If true, droppable elements (with `draggable={true}` attribute)
351
- // can be dropped on the grid. It triggers "onDrop" callback
352
- // with position and event object as parameters.
353
- // It can be useful for dropping an element in a specific position
354
- //
355
- // NOTE: In case of using Firefox you should add
356
- // `onDragStart={e => e.dataTransfer.setData('text/plain', '')}` attribute
357
- // along with `draggable={true}` otherwise this feature will work incorrect.
358
- // onDragStart attribute is required for Firefox for a dragging initialization
359
- // @see https://bugzilla.mozilla.org/show_bug.cgi?id=568313
360
- isDroppable: ?boolean = false,
361
- // Defines which resize handles should be rendered.
362
- // Allows for any combination of:
363
- // 's' - South handle (bottom-center)
364
- // 'w' - West handle (left-center)
365
- // 'e' - East handle (right-center)
366
- // 'n' - North handle (top-center)
367
- // 'sw' - Southwest handle (bottom-left)
368
- // 'nw' - Northwest handle (top-left)
369
- // 'se' - Southeast handle (bottom-right)
370
- // 'ne' - Northeast handle (top-right)
371
- //
372
- // Note that changing this property dynamically does not work due to a restriction in react-resizable.
373
- resizeHandles: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se'],
374
- // Custom component for resize handles
375
- // See `handle` as used in https://github.com/react-grid-layout/react-resizable#resize-handle
376
- // Your component should have the class `.react-resizable-handle`, or you should add your custom
377
- // class to the `draggableCancel` prop.
378
- resizeHandle?: ReactElement<any> | ((resizeHandleAxis: ResizeHandleAxis, ref: ReactRef<HTMLElement>) => ReactElement<any>),
379
-
380
- //
381
- // Callbacks
382
- //
383
-
384
- // Callback so you can save the layout.
385
- // Calls back with (currentLayout) after every drag or resize stop.
386
- onLayoutChange: (layout: Layout) => void,
387
-
388
- //
389
- // All callbacks below have signature (layout, oldItem, newItem, placeholder, e, element).
390
- // 'start' and 'stop' callbacks pass `undefined` for 'placeholder'.
391
- //
392
- type ItemCallback = (layout: Layout, oldItem: LayoutItem, newItem: LayoutItem,
393
- placeholder: LayoutItem, e: MouseEvent, element: HTMLElement) => void,
394
-
395
- // Calls when drag starts.
396
- onDragStart: ItemCallback,
397
- // Calls on each drag movement.
398
- onDrag: ItemCallback,
399
- // Calls when drag is complete.
400
- onDragStop: ItemCallback,
401
- // Calls when resize starts.
402
- onResizeStart: ItemCallback,
403
- // Calls when resize movement happens.
404
- onResize: ItemCallback,
405
- // Calls when resize is complete.
406
- onResizeStop: ItemCallback,
407
-
408
- //
409
- // Dropover functionality
410
- //
411
-
412
- // Calls when an element has been dropped into the grid from outside.
413
- onDrop: (layout: Layout, item: ?LayoutItem, e: Event) => void,
414
- // Calls when an element is being dragged over the grid from outside as above.
415
- // This callback should return an object to dynamically change the droppingItem size
416
- // Return false to short-circuit the dragover
417
- onDropDragOver: (e: DragOverEvent) => ?({|w?: number, h?: number|} | false),
418
-
419
- // Ref for getting a reference for the grid's wrapping div.
420
- // You can use this instead of a regular ref and the deprecated `ReactDOM.findDOMNode()`` function.
421
- // Note that this type is React.Ref<HTMLDivElement> in TypeScript, Flow has a bug here
422
- // https://github.com/facebook/flow/issues/8671#issuecomment-862634865
423
- innerRef: {current: null | HTMLDivElement},
424
- ```
425
-
426
- ### Responsive Grid Layout Props
427
-
428
- The responsive grid layout can be used instead. It supports all of the props above, excepting `layout`.
429
- The new properties and changes are:
336
+ **Why use it instead of WidthProvider?**
430
337
 
431
- ```js
432
- // {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
433
- // Breakpoint names are arbitrary but must match in the cols and layouts objects.
434
- breakpoints: ?Object = {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},
338
+ - Hooks are more composable and easier to test
339
+ - No HOC wrapper means simpler component tree
340
+ - Explicit control over when to render (via `mounted`)
341
+ - Works better with SSR
435
342
 
436
- // # of cols. This is a breakpoint -> cols map, e.g. {lg: 12, md: 10, ...}
437
- cols: ?Object = {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
343
+ ```tsx
344
+ import { useContainerWidth } from "react-grid-layout";
438
345
 
346
+ function MyGrid() {
347
+ const { width, containerRef, mounted, measureWidth } = useContainerWidth({
348
+ measureBeforeMount: false, // Set true for SSR
349
+ initialWidth: 1280 // Width before first measurement
350
+ });
439
351
 
440
- // margin (in pixels). Can be specified either as horizontal and vertical margin, e.g. `[10, 10]` or as a breakpoint -> margin map, e.g. `{lg: [10, 10], md: [10, 10], ...}.
441
- margin: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]},
352
+ return (
353
+ <div ref={containerRef}>{mounted && <ReactGridLayout width={width} />}</div>
354
+ );
355
+ }
356
+ ```
442
357
 
358
+ **Type Definitions:**
443
359
 
444
- // containerPadding (in pixels). Can be specified either as horizontal and vertical padding, e.g. `[10, 10]` or as a breakpoint -> containerPadding map, e.g. `{lg: [10, 10], md: [10, 10], ...}.
445
- containerPadding: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]},
360
+ ```ts
361
+ interface UseContainerWidthOptions {
362
+ /** Delay render until width is measured. Useful for SSR. Default: false */
363
+ measureBeforeMount?: boolean;
364
+ /** Initial width before measurement. Default: 1280 */
365
+ initialWidth?: number;
366
+ }
446
367
 
368
+ interface UseContainerWidthResult {
369
+ /** Current container width in pixels */
370
+ width: number;
371
+ /** Whether the container has been measured at least once */
372
+ mounted: boolean;
373
+ /** Ref to attach to the container element */
374
+ containerRef: RefObject<HTMLDivElement | null>;
375
+ /** Manually trigger a width measurement */
376
+ measureWidth: () => void;
377
+ }
378
+ ```
447
379
 
448
- // layouts is an object mapping breakpoints to layouts.
449
- // e.g. {lg: Layout, md: Layout, ...}
450
- layouts: {[key: $Keys<breakpoints>]: Layout},
380
+ ### useGridLayout
381
+
382
+ Core layout state management hook. Use this when you need direct control over drag/resize/drop state, or when building a custom grid component.
383
+
384
+ **Why use it instead of the component?**
385
+
386
+ - Full control over layout state and updates
387
+ - Access to drag/resize/drop state for custom UIs
388
+ - Can integrate with external state management
389
+ - Build headless grid implementations
390
+
391
+ ```tsx
392
+ import { useGridLayout } from "react-grid-layout";
393
+
394
+ function CustomGrid({ initialLayout }) {
395
+ const {
396
+ layout,
397
+ setLayout,
398
+ dragState,
399
+ resizeState,
400
+ onDragStart,
401
+ onDrag,
402
+ onDragStop,
403
+ onResizeStart,
404
+ onResize,
405
+ onResizeStop,
406
+ containerHeight,
407
+ isInteracting,
408
+ compactor
409
+ } = useGridLayout({
410
+ layout: initialLayout,
411
+ cols: 12,
412
+ compactType: "vertical",
413
+ allowOverlap: false,
414
+ preventCollision: false,
415
+ onLayoutChange: newLayout => console.log("Layout changed:", newLayout)
416
+ });
417
+
418
+ // Access drag state for custom placeholder rendering
419
+ const placeholder = dragState.activeDrag;
420
+
421
+ // Check if any interaction is happening
422
+ if (isInteracting) {
423
+ // Disable other UI during drag/resize
424
+ }
451
425
 
452
- //
453
- // Callbacks
454
- //
426
+ return (
427
+ <div style={{ height: containerHeight * rowHeight }}>
428
+ {layout.map(item => (
429
+ <div
430
+ key={item.i}
431
+ onMouseDown={() => onDragStart(item.i, item.x, item.y)}
432
+ >
433
+ {item.i}
434
+ </div>
435
+ ))}
436
+ {placeholder && <div className="placeholder" />}
437
+ </div>
438
+ );
439
+ }
440
+ ```
455
441
 
456
- // Calls back with breakpoint and new # cols
457
- onBreakpointChange: (newBreakpoint: string, newCols: number) => void,
442
+ **Type Definitions:**
443
+
444
+ ```ts
445
+ interface UseGridLayoutOptions {
446
+ /** Initial layout */
447
+ layout: Layout;
448
+ /** Number of columns */
449
+ cols: number;
450
+ /** Compaction type: 'vertical', 'horizontal', or null */
451
+ compactType?: CompactType;
452
+ /** Allow items to overlap */
453
+ allowOverlap?: boolean;
454
+ /** Prevent collisions when moving items */
455
+ preventCollision?: boolean;
456
+ /** Called when layout changes */
457
+ onLayoutChange?: (layout: Layout) => void;
458
+ }
458
459
 
459
- // Callback so you can save the layout.
460
- // AllLayouts are keyed by breakpoint.
461
- onLayoutChange: (currentLayout: Layout, allLayouts: {[key: $Keys<breakpoints>]: Layout}) => void,
460
+ interface UseGridLayoutResult {
461
+ /** Current layout */
462
+ layout: Layout;
463
+ /** Set layout directly */
464
+ setLayout: (layout: Layout) => void;
465
+ /** Current drag state (activeDrag, oldDragItem, oldLayout) */
466
+ dragState: DragState;
467
+ /** Current resize state (resizing, oldResizeItem, oldLayout) */
468
+ resizeState: ResizeState;
469
+ /** Current drop state (droppingDOMNode, droppingPosition) */
470
+ dropState: DropState;
471
+ /** Start dragging an item */
472
+ onDragStart: (itemId: string, x: number, y: number) => LayoutItem | null;
473
+ /** Update drag position */
474
+ onDrag: (itemId: string, x: number, y: number) => void;
475
+ /** Stop dragging */
476
+ onDragStop: (itemId: string, x: number, y: number) => void;
477
+ /** Start resizing an item */
478
+ onResizeStart: (itemId: string) => LayoutItem | null;
479
+ /** Update resize dimensions */
480
+ onResize: (
481
+ itemId: string,
482
+ w: number,
483
+ h: number,
484
+ x?: number,
485
+ y?: number
486
+ ) => void;
487
+ /** Stop resizing */
488
+ onResizeStop: (itemId: string, w: number, h: number) => void;
489
+ /** Handle external drag over */
490
+ onDropDragOver: (
491
+ droppingItem: LayoutItem,
492
+ position: DroppingPosition
493
+ ) => void;
494
+ /** Handle external drag leave */
495
+ onDropDragLeave: () => void;
496
+ /** Complete external drop */
497
+ onDrop: (droppingItem: LayoutItem) => void;
498
+ /** Container height in grid rows */
499
+ containerHeight: number;
500
+ /** Whether any drag/resize/drop is active */
501
+ isInteracting: boolean;
502
+ /** The compactor being used */
503
+ compactor: Compactor;
504
+ }
505
+ ```
462
506
 
463
- // Callback when the width changes, so you can modify the layout as needed.
464
- onWidthChange: (containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void;
507
+ ### useResponsiveLayout
508
+
509
+ Manages responsive breakpoints and generates layouts for different screen sizes. Use this when building a custom responsive grid.
510
+
511
+ **Why use it instead of the Responsive component?**
512
+
513
+ - Direct access to current breakpoint
514
+ - Control over layout generation for new breakpoints
515
+ - Can update layouts for specific breakpoints
516
+ - Build custom breakpoint UIs
517
+
518
+ ```tsx
519
+ import { useContainerWidth, useResponsiveLayout } from "react-grid-layout";
520
+
521
+ function CustomResponsiveGrid() {
522
+ const { width, containerRef, mounted } = useContainerWidth();
523
+
524
+ const {
525
+ layout, // Current layout for active breakpoint
526
+ layouts, // All layouts by breakpoint
527
+ breakpoint, // Current active breakpoint ('lg', 'md', etc.)
528
+ cols, // Column count for current breakpoint
529
+ setLayoutForBreakpoint,
530
+ setLayouts,
531
+ sortedBreakpoints
532
+ } = useResponsiveLayout({
533
+ width,
534
+ breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
535
+ cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
536
+ layouts: {
537
+ lg: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }],
538
+ md: [{ i: "1", x: 0, y: 0, w: 3, h: 2 }]
539
+ },
540
+ compactType: "vertical",
541
+ onBreakpointChange: (bp, cols) =>
542
+ console.log(`Now at ${bp} (${cols} cols)`),
543
+ onLayoutChange: (layout, allLayouts) => saveToServer(allLayouts)
544
+ });
545
+
546
+ // Show current breakpoint in UI
547
+ return (
548
+ <div ref={containerRef}>
549
+ <div>
550
+ Current breakpoint: {breakpoint} ({cols} columns)
551
+ </div>
552
+ {mounted && (
553
+ <GridLayout width={width} cols={cols} layout={layout}>
554
+ {/* children */}
555
+ </GridLayout>
556
+ )}
557
+ </div>
558
+ );
559
+ }
560
+ ```
561
+
562
+ **Type Definitions:**
563
+
564
+ ```ts
565
+ interface UseResponsiveLayoutOptions<B extends string = DefaultBreakpoints> {
566
+ /** Current container width */
567
+ width: number;
568
+ /** Breakpoint definitions (name → min-width). Default: {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0} */
569
+ breakpoints?: Record<B, number>;
570
+ /** Column counts per breakpoint. Default: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2} */
571
+ cols?: Record<B, number>;
572
+ /** Layouts for each breakpoint */
573
+ layouts?: Partial<Record<B, Layout>>;
574
+ /** Compaction type */
575
+ compactType?: "vertical" | "horizontal" | null;
576
+ /** Called when breakpoint changes */
577
+ onBreakpointChange?: (newBreakpoint: B, cols: number) => void;
578
+ /** Called when layout changes */
579
+ onLayoutChange?: (layout: Layout, layouts: Record<B, Layout>) => void;
580
+ /** Called when width changes */
581
+ onWidthChange?: (
582
+ width: number,
583
+ margin: [number, number],
584
+ cols: number,
585
+ padding: [number, number] | null
586
+ ) => void;
587
+ }
588
+
589
+ interface UseResponsiveLayoutResult<B extends string = DefaultBreakpoints> {
590
+ /** Current layout for the active breakpoint */
591
+ layout: Layout;
592
+ /** All layouts by breakpoint */
593
+ layouts: Partial<Record<B, Layout>>;
594
+ /** Current active breakpoint */
595
+ breakpoint: B;
596
+ /** Column count for the current breakpoint */
597
+ cols: number;
598
+ /** Update layout for a specific breakpoint */
599
+ setLayoutForBreakpoint: (breakpoint: B, layout: Layout) => void;
600
+ /** Update all layouts */
601
+ setLayouts: (layouts: Partial<Record<B, Layout>>) => void;
602
+ /** Sorted array of breakpoint names (smallest to largest) */
603
+ sortedBreakpoints: B[];
604
+ }
465
605
 
606
+ type DefaultBreakpoints = "lg" | "md" | "sm" | "xs" | "xxs";
466
607
  ```
467
608
 
468
- ### Grid Item Props
609
+ ## API Reference
610
+
611
+ ### ReactGridLayout Props
612
+
613
+ The v2 API uses composable configuration interfaces for cleaner prop organization:
614
+
615
+ ```ts
616
+ interface ReactGridLayoutProps {
617
+ // Required
618
+ children: React.ReactNode;
619
+ width: number; // Container width in pixels
620
+
621
+ // Configuration interfaces (see below for details)
622
+ gridConfig?: Partial<GridConfig>; // Grid measurement settings
623
+ dragConfig?: Partial<DragConfig>; // Drag behavior settings
624
+ resizeConfig?: Partial<ResizeConfig>; // Resize behavior settings
625
+ dropConfig?: Partial<DropConfig>; // External drop settings
626
+ positionStrategy?: PositionStrategy; // CSS positioning strategy
627
+ compactor?: Compactor; // Layout compaction strategy
628
+
629
+ // Layout data
630
+ layout?: Layout; // Layout definition
631
+ droppingItem?: LayoutItem; // Item configuration when dropping from outside
632
+
633
+ // Container
634
+ autoSize?: boolean; // Auto-size container height (default: true)
635
+ className?: string;
636
+ style?: React.CSSProperties;
637
+ innerRef?: React.Ref<HTMLDivElement>;
638
+
639
+ // Callbacks
640
+ onLayoutChange?: (layout: Layout) => void;
641
+ onDragStart?: EventCallback;
642
+ onDrag?: EventCallback;
643
+ onDragStop?: EventCallback;
644
+ onResizeStart?: EventCallback;
645
+ onResize?: EventCallback;
646
+ onResizeStop?: EventCallback;
647
+ onDrop?: (layout: Layout, item: LayoutItem | undefined, e: Event) => void;
648
+ onDropDragOver?: (e: DragEvent) => { w?: number; h?: number } | false | void;
649
+ }
650
+ ```
651
+
652
+ ### GridConfig
469
653
 
470
- RGL supports the following properties on grid items or layout items. When initializing a grid,
471
- build a layout array (as in the first example above), or attach this object as the `data-grid` property
472
- to each of your child elements (as in the second example).
654
+ Grid measurement configuration:
655
+
656
+ ```ts
657
+ interface GridConfig {
658
+ cols: number; // Number of columns (default: 12)
659
+ rowHeight: number; // Row height in pixels (default: 150)
660
+ margin: [number, number]; // [x, y] margin between items (default: [10, 10])
661
+ containerPadding: [number, number] | null; // Container padding (default: null, uses margin)
662
+ maxRows: number; // Maximum rows (default: Infinity)
663
+ }
664
+ ```
473
665
 
474
- If `data-grid` is provided on an item, it will take precedence over an item in the `layout` with the same key (`i`).
666
+ ### DragConfig
475
667
 
476
- Note that if a grid item is provided but incomplete (missing one of `x, y, w, or h`), an error
477
- will be thrown so you can correct your layout.
668
+ Drag behavior configuration:
478
669
 
479
- If no properties are provided for a grid item, one will be generated with a width and height of `1`.
670
+ ```ts
671
+ interface DragConfig {
672
+ enabled: boolean; // Enable dragging (default: true)
673
+ bounded: boolean; // Keep items within container (default: false)
674
+ handle?: string; // CSS selector for drag handle
675
+ cancel?: string; // CSS selector to cancel dragging
676
+ threshold: number; // Pixels to move before drag starts (default: 3)
677
+ }
678
+ ```
480
679
 
481
- You can set minimums and maximums for each dimension. This is for resizing; it of course has no effect if resizing
482
- is disabled. Errors will be thrown if your mins and maxes overlap incorrectly, or your initial dimensions
483
- are out of range.
680
+ ### ResizeConfig
484
681
 
485
- Any `<GridItem>` properties defined directly will take precedence over globally-set options. For
486
- example, if the layout has the property `isDraggable: false`, but the grid item has the prop `isDraggable: true`, the item
487
- will be draggable, even if the item is marked `static: true`.
682
+ Resize behavior configuration:
488
683
 
489
- ```js
490
- {
491
-
492
- // A string corresponding to the component key
493
- i: string,
494
-
495
- // These are all in grid units, not pixels
496
- x: number,
497
- y: number,
498
- w: number,
499
- h: number,
500
- minW: ?number = 0,
501
- maxW: ?number = Infinity,
502
- minH: ?number = 0,
503
- maxH: ?number = Infinity,
504
-
505
- // If true, equal to `isDraggable: false, isResizable: false`.
506
- static: ?boolean = false,
507
- // If false, will not be draggable. Overrides `static`.
508
- isDraggable: ?boolean = true,
509
- // If false, will not be resizable. Overrides `static`.
510
- isResizable: ?boolean = true,
511
- // By default, a handle is only shown on the bottom-right (southeast) corner.
512
- // As of RGL >= 1.4.0, resizing on any corner works just fine!
513
- resizeHandles?: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
514
- // If true and draggable, item will be moved only within grid.
515
- isBounded: ?boolean = false
684
+ ```ts
685
+ interface ResizeConfig {
686
+ enabled: boolean; // Enable resizing (default: true)
687
+ handles: ResizeHandleAxis[]; // Handle positions (default: ['se'])
688
+ handleComponent?: React.ReactNode | ((axis, ref) => React.ReactNode);
516
689
  }
517
690
  ```
518
691
 
519
- ### Grid Item Heights and Widths
692
+ ### DropConfig
520
693
 
521
- Grid item widths are based on container and number of columns. The size of a grid unit's height is based on `rowHeight`.
694
+ External drop configuration:
522
695
 
523
- Note that an item that has `h=2` is _not exactly twice as tall as one with `h=1` unless you have no `margin`_!
696
+ ```ts
697
+ interface DropConfig {
698
+ enabled: boolean; // Allow external drops (default: false)
699
+ defaultItem: { w: number; h: number }; // Default size (default: { w: 1, h: 1 })
700
+ onDragOver?: (e: DragEvent) => { w?: number; h?: number } | false | void;
701
+ }
702
+ ```
524
703
 
525
- In order for the grid to not be ragged, when an item spans grid units, it must also span margins. So you must add the height or width or the margin you are spanning for each unit. So actual pixel height is `(rowHeight * h) + (marginH * (h - 1)`.
704
+ ### PositionStrategy
526
705
 
527
- For example, with `rowHeight=30`, `margin=[10,10]` and a unit with height 4, the calculation is `(30 * 4) + (10 * 3)`
706
+ CSS positioning strategy. Built-in options:
528
707
 
529
- ![margin](margin.png)
708
+ ```ts
709
+ import {
710
+ transformStrategy, // Default: use CSS transforms
711
+ absoluteStrategy, // Use top/left positioning
712
+ createScaledStrategy // For scaled containers
713
+ } from "react-grid-layout/core";
530
714
 
531
- If this is a problem for you, set `margin=[0,0]` and handle visual spacing between your elements inside the elements' content.
715
+ // Example: scaled container
716
+ <div style={{ transform: 'scale(0.5)' }}>
717
+ <ReactGridLayout positionStrategy={createScaledStrategy(0.5)} ... />
718
+ </div>
719
+ ```
532
720
 
533
- ### Performance
721
+ ### Compactor
534
722
 
535
- `<ReactGridLayout>` has [an optimized `shouldComponentUpdate` implementation](lib/ReactGridLayout.jsx), but it relies on the user memoizing the `children` array:
723
+ Layout compaction strategy. Built-in options:
536
724
 
537
- ```js
538
- // lib/ReactGridLayout.jsx
539
- // ...
540
- shouldComponentUpdate(nextProps: Props, nextState: State) {
541
- return (
542
- // NOTE: this is almost always unequal. Therefore the only way to get better performance
543
- // from SCU is if the user intentionally memoizes children. If they do, and they can
544
- // handle changes properly, performance will increase.
545
- this.props.children !== nextProps.children ||
546
- !fastRGLPropsEqual(this.props, nextProps, isEqual) ||
547
- !isEqual(this.state.activeDrag, nextState.activeDrag)
548
- );
725
+ ```ts
726
+ import {
727
+ verticalCompactor, // Default: compact items upward
728
+ horizontalCompactor, // Compact items leftward
729
+ noCompactor, // No compaction (free positioning)
730
+ getCompactor // Factory: getCompactor('vertical', allowOverlap, preventCollision)
731
+ } from "react-grid-layout/core";
732
+ ```
733
+
734
+ ### ResponsiveGridLayout Props
735
+
736
+ Extends `GridLayoutProps` with responsive-specific props:
737
+
738
+ ```ts
739
+ interface ResponsiveGridLayoutProps<B extends string = string> {
740
+ // Responsive configuration
741
+ breakpoint?: B; // Current breakpoint (auto-detected)
742
+ breakpoints?: Record<B, number>; // Breakpoint definitions (default: {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0})
743
+ cols?: Record<B, number>; // Columns per breakpoint (default: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2})
744
+ layouts?: Record<B, Layout>; // Layouts per breakpoint
745
+
746
+ // Can be fixed or per-breakpoint
747
+ margin?: [number, number] | Partial<Record<B, [number, number]>>;
748
+ containerPadding?:
749
+ | [number, number]
750
+ | Partial<Record<B, [number, number] | null>>
751
+ | null;
752
+
753
+ // Callbacks
754
+ onBreakpointChange?: (newBreakpoint: B, cols: number) => void;
755
+ onLayoutChange?: (layout: Layout, layouts: Record<B, Layout>) => void;
756
+ onWidthChange?: (
757
+ width: number,
758
+ margin: [number, number],
759
+ cols: number,
760
+ padding: [number, number] | null
761
+ ) => void;
549
762
  }
550
- // ...
551
763
  ```
552
764
 
553
- If you memoize your children, you can take advantage of this, and reap faster rerenders. For example:
765
+ ### Layout Item
766
+
767
+ ```ts
768
+ interface LayoutItem {
769
+ i: string; // Unique identifier (must match child key)
770
+ x: number; // X position in grid units
771
+ y: number; // Y position in grid units
772
+ w: number; // Width in grid units
773
+ h: number; // Height in grid units
774
+ minW?: number; // Minimum width (default: 0)
775
+ maxW?: number; // Maximum width (default: Infinity)
776
+ minH?: number; // Minimum height (default: 0)
777
+ maxH?: number; // Maximum height (default: Infinity)
778
+ static?: boolean; // If true, not draggable or resizable
779
+ isDraggable?: boolean; // Override grid isDraggable
780
+ isResizable?: boolean; // Override grid isResizable
781
+ isBounded?: boolean; // Override grid isBounded
782
+ resizeHandles?: Array<"s" | "w" | "e" | "n" | "sw" | "nw" | "se" | "ne">;
783
+ }
784
+ ```
554
785
 
555
- ```js
556
- function MyGrid(props) {
557
- const children = React.useMemo(() => {
558
- return new Array(props.count).fill(undefined).map((val, idx) => {
559
- return <div key={idx} data-grid={{ x: idx, y: 1, w: 1, h: 1 }} />;
560
- });
561
- }, [props.count]);
562
- return <ReactGridLayout cols={12}>{children}</ReactGridLayout>;
786
+ ### Core Utilities
787
+
788
+ Import pure layout functions from `react-grid-layout/core`:
789
+
790
+ ```ts
791
+ import {
792
+ compact,
793
+ moveElement,
794
+ collides,
795
+ getFirstCollision,
796
+ validateLayout
797
+ // ... and more
798
+ } from "react-grid-layout/core";
799
+ ```
800
+
801
+ ## Extending: Custom Compactors & Position Strategies
802
+
803
+ ### Creating a Custom Compactor
804
+
805
+ Compactors control how items are arranged after drag/resize. Create your own for custom layouts like masonry, gravity, or shelf-packing.
806
+
807
+ **The Compactor Interface:**
808
+
809
+ ```ts
810
+ interface Compactor {
811
+ /** Identifies the compaction type */
812
+ type: "vertical" | "horizontal" | null | string;
813
+
814
+ /** Whether this compactor allows overlapping items */
815
+ allowOverlap: boolean;
816
+
817
+ /** Prevent items from moving when another item is dragged into them */
818
+ preventCollision?: boolean;
819
+
820
+ /**
821
+ * Compact the entire layout.
822
+ * Called after any layout change to fill gaps.
823
+ *
824
+ * @param layout - Array of layout items (clone before mutating!)
825
+ * @param cols - Number of grid columns
826
+ * @returns New compacted layout
827
+ */
828
+ compact(layout: Layout, cols: number): Layout;
829
+
830
+ /**
831
+ * Handle moving an item.
832
+ * Called during drag to preview the new position.
833
+ *
834
+ * @param layout - Current layout
835
+ * @param item - Item being moved
836
+ * @param x - New X position in grid units
837
+ * @param y - New Y position in grid units
838
+ * @param cols - Number of grid columns
839
+ * @returns Updated layout with item at new position
840
+ */
841
+ onMove(
842
+ layout: Layout,
843
+ item: LayoutItem,
844
+ x: number,
845
+ y: number,
846
+ cols: number
847
+ ): Layout;
563
848
  }
564
849
  ```
565
850
 
566
- Because the `children` prop doesn't change between rerenders, updates to `<MyGrid>` won't result in new renders, improving performance.
851
+ **Example: Gravity Compactor (items fall to bottom)**
852
+
853
+ ```ts
854
+ import { cloneLayout, cloneLayoutItem, getStatics, bottom } from "react-grid-layout/core";
855
+
856
+ const gravityCompactor: Compactor = {
857
+ type: "gravity",
858
+ allowOverlap: false,
859
+
860
+ compact(layout, cols) {
861
+ const statics = getStatics(layout);
862
+ const maxY = 100; // arbitrary max height
863
+ const out = [];
864
+
865
+ // Sort by Y descending (process bottom items first)
866
+ const sorted = [...layout].sort((a, b) => b.y - a.y);
867
+
868
+ for (const item of sorted) {
869
+ const l = cloneLayoutItem(item);
870
+
871
+ if (!l.static) {
872
+ // Move down as far as possible
873
+ while (l.y < maxY && !collides(l, statics)) {
874
+ l.y++;
875
+ }
876
+ l.y--; // Back up one
877
+ }
878
+
879
+ out.push(l);
880
+ }
881
+
882
+ return out;
883
+ },
884
+
885
+ onMove(layout, item, x, y, cols) {
886
+ const newLayout = cloneLayout(layout);
887
+ const movedItem = newLayout.find(l => l.i === item.i);
888
+ if (movedItem) {
889
+ movedItem.x = x;
890
+ movedItem.y = y;
891
+ movedItem.moved = true;
892
+ }
893
+ return newLayout;
894
+ }
895
+ };
567
896
 
568
- ### React Hooks Performance
897
+ // Usage
898
+ <GridLayout compactor={gravityCompactor} />
899
+ ```
569
900
 
570
- Using hooks to save your layout state on change will cause the layouts to re-render as the ResponsiveGridLayout will change it's value on every render.
571
- To avoid this you should wrap your WidthProvider in a useMemo:
901
+ **Example: Single Row Compactor (horizontal shelf)**
902
+
903
+ ```ts
904
+ const singleRowCompactor: Compactor = {
905
+ type: "shelf",
906
+ allowOverlap: false,
907
+
908
+ compact(layout, cols) {
909
+ let x = 0;
910
+ const out = [];
911
+
912
+ // Sort by original X position
913
+ const sorted = [...layout].sort((a, b) => a.x - b.x);
914
+
915
+ for (const item of sorted) {
916
+ const l = cloneLayoutItem(item);
917
+ if (!l.static) {
918
+ l.x = x;
919
+ l.y = 0; // All items on row 0
920
+ x += l.w;
921
+
922
+ // Wrap to next row if overflow
923
+ if (x > cols) {
924
+ l.x = 0;
925
+ x = l.w;
926
+ }
927
+ }
928
+ out.push(l);
929
+ }
930
+
931
+ return out;
932
+ },
933
+
934
+ onMove(layout, item, x, y, cols) {
935
+ // Same as default - just update position
936
+ const newLayout = cloneLayout(layout);
937
+ const movedItem = newLayout.find(l => l.i === item.i);
938
+ if (movedItem) {
939
+ movedItem.x = x;
940
+ movedItem.y = 0; // Force row 0
941
+ movedItem.moved = true;
942
+ }
943
+ return newLayout;
944
+ }
945
+ };
946
+ ```
572
947
 
573
- ```js
574
- const ResponsiveReactGridLayout = useMemo(() => WidthProvider(Responsive), []);
948
+ **Using Helper Functions:**
949
+
950
+ The core module exports helpers for building compactors:
951
+
952
+ ```ts
953
+ import {
954
+ resolveCompactionCollision, // Move items to resolve overlaps
955
+ compactItemVertical, // Compact one item upward
956
+ compactItemHorizontal, // Compact one item leftward
957
+ getFirstCollision, // Find first collision
958
+ collides, // Check if two items collide
959
+ getStatics, // Get static items from layout
960
+ cloneLayout, // Clone layout array
961
+ cloneLayoutItem // Clone single item
962
+ } from "react-grid-layout/core";
575
963
  ```
576
964
 
577
- ### Custom Child Components and Draggable Handles
965
+ ### Creating a Custom Position Strategy
966
+
967
+ Position strategies control how items are positioned via CSS. Create custom strategies for special transform handling.
968
+
969
+ **The PositionStrategy Interface:**
970
+
971
+ ```ts
972
+ interface PositionStrategy {
973
+ /** Type identifier */
974
+ type: "transform" | "absolute" | string;
975
+
976
+ /** Scale factor for coordinate calculations */
977
+ scale: number;
978
+
979
+ /**
980
+ * Generate CSS styles for positioning an item.
981
+ *
982
+ * @param pos - Position with top, left, width, height in pixels
983
+ * @returns CSS properties object
984
+ */
985
+ calcStyle(pos: Position): React.CSSProperties;
986
+
987
+ /**
988
+ * Calculate drag position from mouse coordinates.
989
+ * Used during drag to convert screen coords to grid coords.
990
+ *
991
+ * @param clientX - Mouse X position
992
+ * @param clientY - Mouse Y position
993
+ * @param offsetX - Offset from item left edge
994
+ * @param offsetY - Offset from item top edge
995
+ * @returns Calculated left/top position
996
+ */
997
+ calcDragPosition(
998
+ clientX: number,
999
+ clientY: number,
1000
+ offsetX: number,
1001
+ offsetY: number
1002
+ ): { left: number; top: number };
1003
+ }
1004
+ ```
578
1005
 
579
- If you use React Components as grid children, they need to do a few things:
1006
+ **Example: Rotated Container Strategy**
1007
+
1008
+ ```ts
1009
+ const createRotatedStrategy = (angleDegrees: number): PositionStrategy => {
1010
+ const angleRad = (angleDegrees * Math.PI) / 180;
1011
+ const cos = Math.cos(angleRad);
1012
+ const sin = Math.sin(angleRad);
1013
+
1014
+ return {
1015
+ type: "rotated",
1016
+ scale: 1,
1017
+
1018
+ calcStyle(pos) {
1019
+ // Apply rotation to position
1020
+ const rotatedX = pos.left * cos - pos.top * sin;
1021
+ const rotatedY = pos.left * sin + pos.top * cos;
1022
+
1023
+ return {
1024
+ transform: `translate(${rotatedX}px, ${rotatedY}px)`,
1025
+ width: `${pos.width}px`,
1026
+ height: `${pos.height}px`,
1027
+ position: "absolute"
1028
+ };
1029
+ },
1030
+
1031
+ calcDragPosition(clientX, clientY, offsetX, offsetY) {
1032
+ // Reverse the rotation for drag calculations
1033
+ const x = clientX - offsetX;
1034
+ const y = clientY - offsetY;
1035
+
1036
+ return {
1037
+ left: x * cos + y * sin,
1038
+ top: -x * sin + y * cos
1039
+ };
1040
+ }
1041
+ };
1042
+ };
1043
+
1044
+ // Usage: grid inside a rotated container
1045
+ <div style={{ transform: 'rotate(45deg)' }}>
1046
+ <GridLayout positionStrategy={createRotatedStrategy(45)} />
1047
+ </div>
1048
+ ```
580
1049
 
581
- 1. Forward refs to an underlying DOM node, and
582
- 2. Forward `style`,`className`, `onMouseDown`, `onMouseUp` and `onTouchEnd` to that same DOM node.
1050
+ **Example: 3D Perspective Strategy**
1051
+
1052
+ ```ts
1053
+ const create3DStrategy = (
1054
+ perspective: number,
1055
+ rotateX: number
1056
+ ): PositionStrategy => ({
1057
+ type: "3d",
1058
+ scale: 1,
1059
+
1060
+ calcStyle(pos) {
1061
+ return {
1062
+ transform: `
1063
+ perspective(${perspective}px)
1064
+ rotateX(${rotateX}deg)
1065
+ translate3d(${pos.left}px, ${pos.top}px, 0)
1066
+ `,
1067
+ width: `${pos.width}px`,
1068
+ height: `${pos.height}px`,
1069
+ position: "absolute",
1070
+ transformStyle: "preserve-3d"
1071
+ };
1072
+ },
1073
+
1074
+ calcDragPosition(clientX, clientY, offsetX, offsetY) {
1075
+ // Adjust for perspective foreshortening
1076
+ const perspectiveFactor = 1 + clientY / perspective;
1077
+ return {
1078
+ left: (clientX - offsetX) / perspectiveFactor,
1079
+ top: (clientY - offsetY) / perspectiveFactor
1080
+ };
1081
+ }
1082
+ });
1083
+ ```
583
1084
 
584
- For example:
1085
+ ## Extras
1086
+
1087
+ The `react-grid-layout/extras` entry point provides optional components that extend react-grid-layout. These are tree-shakeable and won't be included in your bundle unless explicitly imported.
1088
+
1089
+ ### GridBackground
1090
+
1091
+ Renders an SVG grid background that aligns with GridLayout cells. Use this to visualize the grid structure behind your layout.
1092
+
1093
+ > Based on [PR #2175](https://github.com/react-grid-layout/react-grid-layout/pull/2175) by [@nicosayer](https://github.com/nicosayer).
1094
+
1095
+ ```tsx
1096
+ import { GridBackground } from "react-grid-layout/extras";
1097
+ import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
1098
+
1099
+ function MyGrid() {
1100
+ const { width, containerRef, mounted } = useContainerWidth();
585
1101
 
586
- ```js
587
- const CustomGridItemComponent = React.forwardRef(({style, className, onMouseDown, onMouseUp, onTouchEnd, children, ...props}, ref) => {
588
1102
  return (
589
- <div style={{ /* styles */, ...style}} className={className} ref={ref} onMouseDown={onMouseDown} onMouseUp={onMouseUp} onTouchEnd={onTouchEnd}>
590
- {/* Some other content */}
591
- {children} {/* Make sure to include children to add resizable handle */}
1103
+ <div ref={containerRef} style={{ position: "relative" }}>
1104
+ {mounted && (
1105
+ <>
1106
+ <GridBackground
1107
+ width={width}
1108
+ cols={12}
1109
+ rowHeight={30}
1110
+ margin={[10, 10]}
1111
+ rows={10}
1112
+ color="#f0f0f0"
1113
+ borderRadius={4}
1114
+ />
1115
+ <ReactGridLayout
1116
+ width={width}
1117
+ gridConfig={{ cols: 12, rowHeight: 30, margin: [10, 10] }}
1118
+ >
1119
+ {children}
1120
+ </ReactGridLayout>
1121
+ </>
1122
+ )}
592
1123
  </div>
593
1124
  );
594
- })
1125
+ }
1126
+ ```
1127
+
1128
+ **Props:**
1129
+
1130
+ ```ts
1131
+ interface GridBackgroundProps {
1132
+ // Required - must match your GridLayout config
1133
+ width: number; // Container width
1134
+ cols: number; // Number of columns
1135
+ rowHeight: number; // Row height in pixels
1136
+
1137
+ // Optional
1138
+ margin?: [number, number]; // Gap between cells (default: [10, 10])
1139
+ containerPadding?: [number, number] | null; // Container padding (default: uses margin)
1140
+ rows?: number | "auto"; // Number of rows to display (default: 10)
1141
+ height?: number; // Used when rows="auto" to calculate row count
1142
+ color?: string; // Cell background color (default: "#e0e0e0")
1143
+ borderRadius?: number; // Cell border radius (default: 4)
1144
+ className?: string; // Additional CSS class
1145
+ style?: React.CSSProperties; // Additional inline styles
1146
+ }
1147
+ ```
1148
+
1149
+ ### calcGridCellDimensions (Core Utility)
1150
+
1151
+ For building custom grid overlays or backgrounds, use the `calcGridCellDimensions` utility from `react-grid-layout/core`:
1152
+
1153
+ ```ts
1154
+ import { calcGridCellDimensions } from "react-grid-layout/core";
1155
+
1156
+ const dims = calcGridCellDimensions({
1157
+ width: 1200,
1158
+ cols: 12,
1159
+ rowHeight: 30,
1160
+ margin: [10, 10],
1161
+ containerPadding: [20, 20]
1162
+ });
1163
+
1164
+ // dims = {
1165
+ // cellWidth: 88.33, // Width of each cell
1166
+ // cellHeight: 30, // Height of each cell (= rowHeight)
1167
+ // offsetX: 20, // Left padding
1168
+ // offsetY: 20, // Top padding
1169
+ // gapX: 10, // Horizontal gap between cells
1170
+ // gapY: 10, // Vertical gap between cells
1171
+ // cols: 12, // Column count
1172
+ // containerWidth: 1200
1173
+ // }
1174
+ ```
1175
+
1176
+ This is useful for building custom visualizations, snap-to-grid functionality, or integrating with canvas/WebGL renderers.
1177
+
1178
+ ## Performance
1179
+
1180
+ ### Memoize Children
1181
+
1182
+ The grid compares children by reference. Memoize them for better performance:
1183
+
1184
+ ```tsx
1185
+ function MyGrid({ count, width }) {
1186
+ const children = useMemo(() => {
1187
+ return Array.from({ length: count }, (_, i) => (
1188
+ <div
1189
+ key={i}
1190
+ data-grid={{ x: i % 12, y: Math.floor(i / 12), w: 1, h: 1 }}
1191
+ />
1192
+ ));
1193
+ }, [count]);
1194
+
1195
+ return (
1196
+ <ReactGridLayout width={width} gridConfig={{ cols: 12 }}>
1197
+ {children}
1198
+ </ReactGridLayout>
1199
+ );
1200
+ }
595
1201
  ```
596
1202
 
597
- The same is true of custom elements as draggable handles using the `draggableHandle` prop. This is so that
598
- the underlying `react-draggable` library can get a reference to the DOM node underneath, manipulate
599
- positioning via `style`, and set classes.
1203
+ ### Avoid Creating Components in Render (Legacy WidthProvider)
1204
+
1205
+ If using the legacy WidthProvider HOC, don't create the component during render:
1206
+
1207
+ ```tsx
1208
+ import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";
1209
+
1210
+ // Bad - creates new component every render
1211
+ function MyGrid() {
1212
+ const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
1213
+ return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
1214
+ }
1215
+
1216
+ // Good - create once outside or with useMemo
1217
+ const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
1218
+
1219
+ function MyGrid() {
1220
+ return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
1221
+ }
1222
+ ```
1223
+
1224
+ With the v2 API, use `useContainerWidth` hook instead to avoid this issue entirely.
1225
+
1226
+ ## Custom Child Components
1227
+
1228
+ Grid children must forward refs and certain props:
1229
+
1230
+ ```tsx
1231
+ const CustomItem = forwardRef<HTMLDivElement, CustomItemProps>(
1232
+ (
1233
+ {
1234
+ style,
1235
+ className,
1236
+ onMouseDown,
1237
+ onMouseUp,
1238
+ onTouchEnd,
1239
+ children,
1240
+ ...props
1241
+ },
1242
+ ref
1243
+ ) => {
1244
+ return (
1245
+ <div
1246
+ ref={ref}
1247
+ style={style}
1248
+ className={className}
1249
+ onMouseDown={onMouseDown}
1250
+ onMouseUp={onMouseUp}
1251
+ onTouchEnd={onTouchEnd}
1252
+ >
1253
+ {children}
1254
+ </div>
1255
+ );
1256
+ }
1257
+ );
1258
+ ```
600
1259
 
601
1260
  ## Contribute
602
1261
 
@@ -604,19 +1263,3 @@ If you have a feature request, please add it as an issue or make a pull request.
604
1263
 
605
1264
  If you have a bug to report, please reproduce the bug in [CodeSandbox](https://codesandbox.io/s/staging-bush-3lvt7?file=/src/ShowcaseLayout.js) to help
606
1265
  us easily isolate it.
607
-
608
- ## TODO List
609
-
610
- - [x] Basic grid layout
611
- - [x] Fluid grid layout
612
- - [x] Grid packing
613
- - [x] Draggable grid items
614
- - [x] Live grid packing while dragging
615
- - [x] Resizable grid items
616
- - [x] Layouts per responsive breakpoint
617
- - [x] Define grid attributes on children themselves (`data-grid` key)
618
- - [x] Static elements
619
- - [x] Persistent id per item for predictable localstorage restores, even when # items changes
620
- - [x] Min/max w/h per item
621
- - [x] Resizable handles on other corners
622
- - [ ] Configurable w/h per breakpoint