@ad2302/react-grid-layout 中文文档教程
React-Grid-Layout
React-Grid-Layout 是一个网格布局系统很像 Packery 或者 Gridster,用于 React。
与那些系统不同,它具有响应能力并支持断点。 断点布局可以由用户提供 或自动生成。
RGL 仅支持 React,不需要 jQuery。
GIF 来自 BitMEX.com 上的生产使用
[演示 | 变更日志 | CodeSandbox Editable demo]
Table of Contents
- Demos
- Features
- Installation
- Usage
- Responsive Usage
- Providing Grid Width
- Grid Layout Props
- Responsive Grid Layout Props
- Grid Item Props
- User Recipes
- Performance
- Contribute
- TODO List
Demos
- Showcase
- Basic
- No Dragging/Resizing (Layout Only)
- Messy Layout Autocorrect
- Layout Defined on Children
- Static Elements
- Adding/Removing Elements
- Saving Layout to LocalStorage
- Saving a Responsive Layout to LocalStorage
- Minimum and Maximum Width/Height
- Dynamic Minimum and Maximum Width/Height
- No Vertical Compacting (Free Movement)
- Prevent Collision
- Error Case
- Toolbox
- Drag From Outside
- Bounded Layout
- Resizable Handles
- Scaled Containers
Projects Using React-Grid-Layout
- BitMEX
- AWS CloudFront Dashboards
- Grafana
- Metabase
- HubSpot
- ComNetViz
- Stoplight
- Reflect
- ez-Dashing
- Kibana
- Graphext
- Monday
- Quadency
- Hakkiri
- Ubidots
- Statsout
- Datto RMM
认识其他人吗? 创建一个 PR 让我知道!
Features
- 100% React - no jQuery
- Compatible with server-rendered apps
- Draggable widgets
- Resizable widgets
- Static widgets
- Configurable packing: horizontal, vertical, or off
- Bounds checking for dragging and resizing
- Widgets may be added or removed without rebuilding grid
- Layout can be serialized and restored
- Responsive breakpoints
- Separate layouts per responsive breakpoint
- Grid Items placed using CSS Transforms
- Performance with CSS Transforms: on / off, note paint (green) as % of time
- Compatibility with
<React.StrictMode>
Version | Compatibility |
---|---|
>= 0.17.0 | React 16 & 17 |
>= 0.11.3 | React 0.14 & 15 |
>= 0.10.0 | React 0.14 |
0.8. - 0.9.2 | React 0.13 |
< 0.8 | React 0.12 |
Installation
安装 React-Grid-Layout package 包使用npm:
npm install react-grid-layout
在您的应用程序中包含以下样式表:
/node_modules/react-grid-layout/css/styles.css
/node_modules/react-resizable/css/styles.css
Usage
像使用任何其他组件一样使用 ReactGridLayout。 以下示例将 生成一个包含三个项目的网格,其中:
- users will not be able to drag or resize item
a
- item
b
will be restricted to a minimum width of 2 grid blocks and a maximum width of 4 grid blocks - users will be able to freely drag and resize item
c
import GridLayout from 'react-grid-layout';
class MyFirstGrid extends React.Component {
render() {
// layout is an array of objects, see the demo for more complete usage
const layout = [
{i: 'a', x: 0, y: 0, w: 1, h: 2, static: true},
{i: 'b', x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4},
{i: 'c', x: 4, y: 0, w: 1, h: 2}
];
return (
<GridLayout className="layout" layout={layout} cols={12} rowHeight={30} width={1200}>
<div key="a">a</div>
<div key="b">b</div>
<div key="c">c</div>
</GridLayout>
)
}
}
您也可以选择直接在子项上设置布局属性:
import GridLayout from 'react-grid-layout';
class MyFirstGrid extends React.Component {
render() {
return (
<GridLayout className="layout" cols={12} rowHeight={30} width={1200}>
<div key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}>a</div>
<div key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}>b</div>
<div key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}>c</div>
</GridLayout>
)
}
}
Usage without Browserify/Webpack
包含一个可用于 标签的模块 这里。 它使用 UMD 垫片和
不包括
React
,因此它必须以其他方式在您的应用程序中可用,无论是通过 RequireJS 还是在 window.React
上。
Responsive Usage
要使 RGL 响应,请使用
元素:
import { Responsive as ResponsiveGridLayout } from 'react-grid-layout';
class MyResponsiveGrid extends React.Component {
render() {
// {lg: layout1, md: layout2, ...}
const layouts = getLayoutsFromSomewhere();
return (
<ResponsiveGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveGridLayout>
)
}
}
当处于响应模式时,您应该通过 layouts
属性提供至少一个断点。
使用 layouts
时,最好提供尽可能多的断点,尤其是最大的断点。 如果提供了最大的,RGL 将尝试对其余的进行插值。
您还需要提供一个宽度
,在使用
时建议您使用HOC WidthProvider
按照下面的说明。
可以通过个人的 data-grid
属性提供默认映射 项目,以便在布局插值中考虑它们。
Providing Grid Width
和
都取width
来计算 拖动事件的位置。 在简单的情况下,HOC WidthProvider
可用于自动确定 初始化和窗口调整大小事件时的宽度。
import { Responsive, WidthProvider } from 'react-grid-layout';
const ResponsiveGridLayout = WidthProvider(Responsive);
class MyResponsiveGrid extends React.Component {
render() {
// {lg: layout1, md: layout2, ...}
var layouts = getLayoutsFromSomewhere();
return (
<ResponsiveGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveGridLayout>
)
}
}
如果您需要更复杂的逻辑,这使您可以轻松地将 WidthProvider
替换为您自己的 Provider HOC。
WidthProvider
接受单个道具 measureBeforeMount
。 如果 true
,WidthProvider
将测量 安装孩子之前容器的宽度。 如果您想完全消除任何调整大小的动画,请使用它 在应用程序/组件安装上。
有更复杂的布局? WidthProvider
非常简单而且只有 监听窗口 'resize'
事件。 如果您需要更强大的功能和灵活性,请尝试 SizeMe React HOC 作为 WidthProvider 的替代品。
Grid Layout Props
RGL 支持以下属性(请参阅源代码以了解最终
//
// Basic props
//
// This allows setting the initial width on the server side.
// This is required unless using the HOC <WidthProvider> or similar
width: number,
// If true, the container height swells and contracts to fit contents
autoSize: ?boolean = true,
// Number of columns in this layout.
cols: ?number = 12,
// A CSS selector for tags that will not be draggable.
// For example: draggableCancel:'.MyNonDraggableAreaClassName'
// If you forget the leading . it will not work.
// .react-resizable-handle" is always prepended to this value.
draggableCancel: ?string = '',
// A CSS selector for tags that will act as the draggable handle.
// For example: draggableHandle:'.MyDragHandleClassName'
// If you forget the leading . it will not work.
draggableHandle: ?string = '',
// Compaction type.
compactType: ?('vertical' | 'horizontal') = 'vertical';
// Layout is an array of object with the format:
// {x: number, y: number, w: number, h: number}
// The index into the layout must match the key used on each item component.
// If you choose to use custom keys, you can specify that key in the layout
// array objects like so:
// {i: string, x: number, y: number, w: number, h: number}
layout: ?array = null, // If not provided, use data-grid props on children
// Margin between items [x, y] in px.
margin: ?[number, number] = [10, 10],
// Padding inside the container [x, y] in px
containerPadding: ?[number, number] = margin,
// Rows have a static height, but you can change this based on breakpoints
// if you like.
rowHeight: ?number = 150,
// Configuration of a dropping element. Dropping element is a "virtual" element
// which appears when you drag over some element from outside.
// It can be changed by passing specific parameters:
// i - id of an element
// w - width of an element
// h - height of an element
droppingItem?: { i: string, w: number, h: number }
//
// Flags
//
isDraggable: ?boolean = true,
isResizable: ?boolean = true,
isBounded: ?boolean = false,
// Uses CSS3 translate() instead of position top/left.
// This makes about 6x faster paint performance
useCSSTransforms: ?boolean = true,
// If parent DOM node of ResponsiveReactGridLayout or ReactGridLayout has "transform: scale(n)" css property,
// we should set scale coefficient to avoid render artefacts while dragging.
transformScale: ?number = 1,
// If true, grid items won't change position when being
// dragged over.
preventCollision: ?boolean = false;
// If true, droppable elements (with `draggable={true}` attribute)
// can be dropped on the grid. It triggers "onDrop" callback
// with position and event object as parameters.
// It can be useful for dropping an element in a specific position
//
// NOTE: In case of using Firefox you should add
// `onDragStart={e => e.dataTransfer.setData('text/plain', '')}` attribute
// along with `draggable={true}` otherwise this feature will work incorrect.
// onDragStart attribute is required for Firefox for a dragging initialization
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=568313
isDroppable: ?boolean = false
// Defines which resize handles should be rendered
// Allows for any combination of:
// 's' - South handle (bottom-center)
// 'w' - West handle (left-center)
// 'e' - East handle (right-center)
// 'n' - North handle (top-center)
// 'sw' - Southwest handle (bottom-left)
// 'nw' - Northwest handle (top-left)
// 'se' - Southeast handle (bottom-right)
// 'ne' - Northeast handle (top-right)
resizeHandles: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
// Custom component for resize handles
// See `handle` as used in https://github.com/react-grid-layout/react-resizable#resize-handle
// Your component should have the class `.react-resizable-handle`, or you should add your custom
// class to the `draggableCancel` prop.
resizeHandle?: ReactElement<any> | ((resizeHandleAxis: ResizeHandleAxis, ref: ReactRef<HTMLElement>) => ReactElement<any>)
//
// Callbacks
//
// Callback so you can save the layout.
// Calls back with (currentLayout) after every drag or resize stop.
onLayoutChange: (layout: Layout) => void,
//
// All callbacks below have signature (layout, oldItem, newItem, placeholder, e, element).
// 'start' and 'stop' callbacks pass `undefined` for 'placeholder'.
//
type ItemCallback = (layout: Layout, oldItem: LayoutItem, newItem: LayoutItem,
placeholder: LayoutItem, e: MouseEvent, element: HTMLElement) => void;
// Calls when drag starts.
onDragStart: ItemCallback,
// Calls on each drag movement.
onDrag: ItemCallback,
// Calls when drag is complete.
onDragStop: ItemCallback,
// Calls when resize starts.
onResizeStart: ItemCallback,
// Calls when resize movement happens.
onResize: ItemCallback,
// Calls when resize is complete.
onResizeStop: ItemCallback,
//
// Dropover functionality
//
// Calls when an element has been dropped into the grid from outside.
onDrop: (layout: Layout, item: ?LayoutItem, e: Event) => void
// Calls when an element is being dragged over the grid from outside as above.
// This callback should return an object to dynamically change the droppingItem size
// Return false to short-circuit the dragover
onDropDragOver: (e: DragOverEvent) => ?({|w?: number, h?: number|} | false);
// Ref for getting a reference for the grid's wrapping div.
// You can use this instead of a regular ref and the deprecated `ReactDOM.findDOMNode()`` function.
innerRef: ?React.Ref<"div">
Responsive Grid Layout Props
结果): 可以改用响应式网格布局。 它支持上述所有属性,layout
除外。 新属性和更改是:
// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
// Breakpoint names are arbitrary but must match in the cols and layouts objects.
breakpoints: ?Object = {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},
// # of cols. This is a breakpoint -> cols map, e.g. {lg: 12, md: 10, ...}
cols: ?Object = {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
// 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], ...}.
margin: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]}
// 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], ...}.
containerPadding: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]}
// layouts is an object mapping breakpoints to layouts.
// e.g. {lg: Layout, md: Layout, ...}
layouts: {[key: $Keys<breakpoints>]: Layout}
//
// Callbacks
//
// Calls back with breakpoint and new # cols
onBreakpointChange: (newBreakpoint: string, newCols: number) => void,
// Callback so you can save the layout.
// AllLayouts are keyed by breakpoint.
onLayoutChange: (currentLayout: Layout, allLayouts: {[key: $Keys<breakpoints>]: Layout}) => void,
// Callback when the width changes, so you can modify the layout as needed.
onWidthChange: (containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void;
Grid Item Props
RGL 支持网格项或布局项的以下属性。 初始化网格时, 构建布局数组(如上面的第一个示例),或将此对象附加为 data-grid
属性 给你的每个子元素(如第二个例子)。
请注意,如果提供了网格项但不完整(缺少 x、y、w 或 h
之一),则会出错 将被抛出,以便您可以更正布局。
如果没有为网格项提供属性,则将生成宽度和高度为 1
的属性。
您可以为每个维度设置最小值和最大值。 这是为了调整大小; 如果调整大小当然没有效果 被禁用。 如果您的最小值和最大值重叠不正确,或者您的初始尺寸,将会抛出错误 超出范围。
直接定义的任何
属性都将优先于全局设置的选项。 为了 例如,如果布局具有属性 isDraggable: false
,但网格项目具有属性 isDraggable: true
,则项目 将是可拖动的,即使该项目被标记为 static: true
。
{
// A string corresponding to the component key
i: string,
// These are all in grid units, not pixels
x: number,
y: number,
w: number,
h: number,
minW: ?number = 0,
maxW: ?number = Infinity,
minH: ?number = 0,
maxH: ?number = Infinity,
// If true, equal to `isDraggable: false, isResizable: false`.
static: ?boolean = false,
// If false, will not be draggable. Overrides `static`.
isDraggable: ?boolean = true,
// If false, will not be resizable. Overrides `static`.
isResizable: ?boolean = true,
// By default, a handle is only shown on the bottom-right (southeast) corner.
// Note that resizing from the top or left is generally not intuitive.
resizeHandles?: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
// If true and draggable, item will be moved only within grid.
isBounded: ?boolean = false
}
Performance
具有优化的shouldComponentUpdate
实现,但它依赖于用户记忆children
数组:
// lib/ReactGridLayout.jsx
// ...
shouldComponentUpdate(nextProps: Props, nextState: State) {
return (
// NOTE: this is almost always unequal. Therefore the only way to get better performance
// from SCU is if the user intentionally memoizes children. If they do, and they can
// handle changes properly, performance will increase.
this.props.children !== nextProps.children ||
!fastRGLPropsEqual(this.props, nextProps, isEqual) ||
!isEqual(this.state.activeDrag, nextState.activeDrag)
);
}
// ...
如果你记忆你的孩子,你可以利用它,并获得更快的重新渲染。 例如:
function MyGrid(props) {
const children = React.useMemo(() => {
return new Array(props.count).fill(undefined).map((val, idx) => {
return <div key={idx} data-grid={{x: idx, y: 1, w: 1, h: 1}} />;
});
}, [props.count]);
return <ReactGridLayout cols={12}>{children}</ReactGridLayout>;
}
因为 children
道具在重新渲染之间不会改变,所以对
的更新不会导致新的渲染,从而提高性能。
Custom Child Components and Draggable Handles
如果您将 React 组件用作网格子项,则它们需要做一些事情:
- Forward refs to an underlying DOM node, and
- Forward
style
andclassName
to that same DOM node.
例如:
const CustomGridItemComponent = React.forwardRef(({style, className, ...props}, ref) => {
return (
<div style={{ /* styles */, ...style}} className={className} ref={ref}>
{/* Some other content */}
</div>
);
}
使用 draggableHandle
属性将自定义元素作为可拖动句柄也是如此。 这是为了 底层的 react-draggable
库可以获得对下面 DOM 节点的引用,操作 通过style
定位,并设置类。
Contribute
如果您有功能请求,请将其添加为问题或提出拉取请求。
如果您有错误要报告,请在 CodeSandbox 中重现错误以提供帮助 我们很容易隔离它。
TODO List
- [x] Basic grid layout
- [x] Fluid grid layout
- [x] Grid packing
- [x] Draggable grid items
- [x] Live grid packing while dragging
- [x] Resizable grid items
- [x] Layouts per responsive breakpoint
- [x] Define grid attributes on children themselves (
data-grid
key) - [x] Static elements
- [x] Persistent id per item for predictable localstorage restores, even when # items changes
- [x] Min/max w/h per item
- [ ] Resizable handles on other corners
- [ ] Configurable w/h per breakpoint
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 supports breakpoints. Breakpoint layouts can be provided by the user or autogenerated.
RGL is React-only and does not require jQuery.
GIF from production usage on BitMEX.com
[Demo | Changelog | CodeSandbox Editable demo]
Table of Contents
- Demos
- Features
- Installation
- Usage
- Responsive Usage
- Providing Grid Width
- Grid Layout Props
- Responsive Grid Layout Props
- Grid Item Props
- User Recipes
- Performance
- Contribute
- TODO List
Demos
- Showcase
- Basic
- No Dragging/Resizing (Layout Only)
- Messy Layout Autocorrect
- Layout Defined on Children
- Static Elements
- Adding/Removing Elements
- Saving Layout to LocalStorage
- Saving a Responsive Layout to LocalStorage
- Minimum and Maximum Width/Height
- Dynamic Minimum and Maximum Width/Height
- No Vertical Compacting (Free Movement)
- Prevent Collision
- Error Case
- Toolbox
- Drag From Outside
- Bounded Layout
- Resizable Handles
- Scaled Containers
Projects Using React-Grid-Layout
- BitMEX
- AWS CloudFront Dashboards
- Grafana
- Metabase
- HubSpot
- ComNetViz
- Stoplight
- Reflect
- ez-Dashing
- Kibana
- Graphext
- Monday
- Quadency
- Hakkiri
- Ubidots
- Statsout
- Datto RMM
Know of others? Create a PR to let me know!
Features
- 100% React - no jQuery
- Compatible with server-rendered apps
- Draggable widgets
- Resizable widgets
- Static widgets
- Configurable packing: horizontal, vertical, or off
- Bounds checking for dragging and resizing
- Widgets may be added or removed without rebuilding grid
- Layout can be serialized and restored
- Responsive breakpoints
- Separate layouts per responsive breakpoint
- Grid Items placed using CSS Transforms
- Performance with CSS Transforms: on / off, note paint (green) as % of time
- Compatibility with
<React.StrictMode>
Version | Compatibility |
---|---|
>= 0.17.0 | React 16 & 17 |
>= 0.11.3 | React 0.14 & 15 |
>= 0.10.0 | React 0.14 |
0.8. - 0.9.2 | React 0.13 |
< 0.8 | React 0.12 |
Installation
Install the React-Grid-Layout package package using npm:
npm install react-grid-layout
Include the following stylesheets in your application:
/node_modules/react-grid-layout/css/styles.css
/node_modules/react-resizable/css/styles.css
Usage
Use ReactGridLayout like any other component. The following example below will produce a grid with three items where:
- users will not be able to drag or resize item
a
- item
b
will be restricted to a minimum width of 2 grid blocks and a maximum width of 4 grid blocks - users will be able to freely drag and resize item
c
import GridLayout from 'react-grid-layout';
class MyFirstGrid extends React.Component {
render() {
// layout is an array of objects, see the demo for more complete usage
const layout = [
{i: 'a', x: 0, y: 0, w: 1, h: 2, static: true},
{i: 'b', x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4},
{i: 'c', x: 4, y: 0, w: 1, h: 2}
];
return (
<GridLayout className="layout" layout={layout} cols={12} rowHeight={30} width={1200}>
<div key="a">a</div>
<div key="b">b</div>
<div key="c">c</div>
</GridLayout>
)
}
}
You may also choose to set layout properties directly on the children:
import GridLayout from 'react-grid-layout';
class MyFirstGrid extends React.Component {
render() {
return (
<GridLayout className="layout" cols={12} rowHeight={30} width={1200}>
<div key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}>a</div>
<div key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}>b</div>
<div key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}>c</div>
</GridLayout>
)
}
}
Usage without Browserify/Webpack
A module usable in a <script>
tag is included here. It uses a UMD shim and excludes React
, so it must be otherwise available in your application, either via RequireJS or on window.React
.
Responsive Usage
To make RGL responsive, use the <ResponsiveReactGridLayout>
element:
import { Responsive as ResponsiveGridLayout } from 'react-grid-layout';
class MyResponsiveGrid extends React.Component {
render() {
// {lg: layout1, md: layout2, ...}
const layouts = getLayoutsFromSomewhere();
return (
<ResponsiveGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveGridLayout>
)
}
}
When in responsive mode, you should supply at least one breakpoint via the layouts
property.
When using layouts
, it is best to supply as many breakpoints as possible, especially the largest one. If the largest is provided, RGL will attempt to interpolate the rest.
You will also need to provide a width
, when using <ResponsiveReactGridLayout>
it is suggested you use the HOC WidthProvider
as per the instructions below.
It is possible to supply default mappings via the data-grid
property on individual items, so that they would be taken into account within layout interpolation.
Providing Grid Width
Both <ResponsiveReactGridLayout>
and <ReactGridLayout>
take width
to calculate positions on drag events. In simple cases a HOC WidthProvider
can be used to automatically determine width upon initialization and window resize events.
import { Responsive, WidthProvider } from 'react-grid-layout';
const ResponsiveGridLayout = WidthProvider(Responsive);
class MyResponsiveGrid extends React.Component {
render() {
// {lg: layout1, md: layout2, ...}
var layouts = getLayoutsFromSomewhere();
return (
<ResponsiveGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveGridLayout>
)
}
}
This allows you to easily replace WidthProvider
with your own Provider HOC if you need more sophisticated logic.
WidthProvider
accepts a single prop, measureBeforeMount
. If true
, WidthProvider
will measure the container's width before mounting children. Use this if you'd like to completely eliminate any resizing animation on application/component mount.
Have a more complicated layout? WidthProvider
is very simple and only listens to window 'resize'
events. If you need more power and flexibility, try the SizeMe React HOC as an alternative to WidthProvider.
Grid Layout Props
RGL supports the following properties (see the source for the final word on this):
//
// Basic props
//
// This allows setting the initial width on the server side.
// This is required unless using the HOC <WidthProvider> or similar
width: number,
// If true, the container height swells and contracts to fit contents
autoSize: ?boolean = true,
// Number of columns in this layout.
cols: ?number = 12,
// A CSS selector for tags that will not be draggable.
// For example: draggableCancel:'.MyNonDraggableAreaClassName'
// If you forget the leading . it will not work.
// .react-resizable-handle" is always prepended to this value.
draggableCancel: ?string = '',
// A CSS selector for tags that will act as the draggable handle.
// For example: draggableHandle:'.MyDragHandleClassName'
// If you forget the leading . it will not work.
draggableHandle: ?string = '',
// Compaction type.
compactType: ?('vertical' | 'horizontal') = 'vertical';
// Layout is an array of object with the format:
// {x: number, y: number, w: number, h: number}
// The index into the layout must match the key used on each item component.
// If you choose to use custom keys, you can specify that key in the layout
// array objects like so:
// {i: string, x: number, y: number, w: number, h: number}
layout: ?array = null, // If not provided, use data-grid props on children
// Margin between items [x, y] in px.
margin: ?[number, number] = [10, 10],
// Padding inside the container [x, y] in px
containerPadding: ?[number, number] = margin,
// Rows have a static height, but you can change this based on breakpoints
// if you like.
rowHeight: ?number = 150,
// Configuration of a dropping element. Dropping element is a "virtual" element
// which appears when you drag over some element from outside.
// It can be changed by passing specific parameters:
// i - id of an element
// w - width of an element
// h - height of an element
droppingItem?: { i: string, w: number, h: number }
//
// Flags
//
isDraggable: ?boolean = true,
isResizable: ?boolean = true,
isBounded: ?boolean = false,
// Uses CSS3 translate() instead of position top/left.
// This makes about 6x faster paint performance
useCSSTransforms: ?boolean = true,
// If parent DOM node of ResponsiveReactGridLayout or ReactGridLayout has "transform: scale(n)" css property,
// we should set scale coefficient to avoid render artefacts while dragging.
transformScale: ?number = 1,
// If true, grid items won't change position when being
// dragged over.
preventCollision: ?boolean = false;
// If true, droppable elements (with `draggable={true}` attribute)
// can be dropped on the grid. It triggers "onDrop" callback
// with position and event object as parameters.
// It can be useful for dropping an element in a specific position
//
// NOTE: In case of using Firefox you should add
// `onDragStart={e => e.dataTransfer.setData('text/plain', '')}` attribute
// along with `draggable={true}` otherwise this feature will work incorrect.
// onDragStart attribute is required for Firefox for a dragging initialization
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=568313
isDroppable: ?boolean = false
// Defines which resize handles should be rendered
// Allows for any combination of:
// 's' - South handle (bottom-center)
// 'w' - West handle (left-center)
// 'e' - East handle (right-center)
// 'n' - North handle (top-center)
// 'sw' - Southwest handle (bottom-left)
// 'nw' - Northwest handle (top-left)
// 'se' - Southeast handle (bottom-right)
// 'ne' - Northeast handle (top-right)
resizeHandles: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
// Custom component for resize handles
// See `handle` as used in https://github.com/react-grid-layout/react-resizable#resize-handle
// Your component should have the class `.react-resizable-handle`, or you should add your custom
// class to the `draggableCancel` prop.
resizeHandle?: ReactElement<any> | ((resizeHandleAxis: ResizeHandleAxis, ref: ReactRef<HTMLElement>) => ReactElement<any>)
//
// Callbacks
//
// Callback so you can save the layout.
// Calls back with (currentLayout) after every drag or resize stop.
onLayoutChange: (layout: Layout) => void,
//
// All callbacks below have signature (layout, oldItem, newItem, placeholder, e, element).
// 'start' and 'stop' callbacks pass `undefined` for 'placeholder'.
//
type ItemCallback = (layout: Layout, oldItem: LayoutItem, newItem: LayoutItem,
placeholder: LayoutItem, e: MouseEvent, element: HTMLElement) => void;
// Calls when drag starts.
onDragStart: ItemCallback,
// Calls on each drag movement.
onDrag: ItemCallback,
// Calls when drag is complete.
onDragStop: ItemCallback,
// Calls when resize starts.
onResizeStart: ItemCallback,
// Calls when resize movement happens.
onResize: ItemCallback,
// Calls when resize is complete.
onResizeStop: ItemCallback,
//
// Dropover functionality
//
// Calls when an element has been dropped into the grid from outside.
onDrop: (layout: Layout, item: ?LayoutItem, e: Event) => void
// Calls when an element is being dragged over the grid from outside as above.
// This callback should return an object to dynamically change the droppingItem size
// Return false to short-circuit the dragover
onDropDragOver: (e: DragOverEvent) => ?({|w?: number, h?: number|} | false);
// Ref for getting a reference for the grid's wrapping div.
// You can use this instead of a regular ref and the deprecated `ReactDOM.findDOMNode()`` function.
innerRef: ?React.Ref<"div">
Responsive Grid Layout Props
The responsive grid layout can be used instead. It supports all of the props above, excepting layout
. The new properties and changes are:
// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
// Breakpoint names are arbitrary but must match in the cols and layouts objects.
breakpoints: ?Object = {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},
// # of cols. This is a breakpoint -> cols map, e.g. {lg: 12, md: 10, ...}
cols: ?Object = {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
// 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], ...}.
margin: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]}
// 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], ...}.
containerPadding: [number, number] | {[breakpoint: $Keys<breakpoints>]: [number, number]}
// layouts is an object mapping breakpoints to layouts.
// e.g. {lg: Layout, md: Layout, ...}
layouts: {[key: $Keys<breakpoints>]: Layout}
//
// Callbacks
//
// Calls back with breakpoint and new # cols
onBreakpointChange: (newBreakpoint: string, newCols: number) => void,
// Callback so you can save the layout.
// AllLayouts are keyed by breakpoint.
onLayoutChange: (currentLayout: Layout, allLayouts: {[key: $Keys<breakpoints>]: Layout}) => void,
// Callback when the width changes, so you can modify the layout as needed.
onWidthChange: (containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void;
Grid Item Props
RGL supports the following properties on grid items or layout items. When initializing a grid, build a layout array (as in the first example above), or attach this object as the data-grid
property to each of your child elements (as in the second example).
Note that if a grid item is provided but incomplete (missing one of x, y, w, or h
), an error will be thrown so you can correct your layout.
If no properties are provided for a grid item, one will be generated with a width and height of 1
.
You can set minimums and maximums for each dimension. This is for resizing; it of course has no effect if resizing is disabled. Errors will be thrown if your mins and maxes overlap incorrectly, or your initial dimensions are out of range.
Any <GridItem>
properties defined directly will take precedence over globally-set options. For example, if the layout has the property isDraggable: false
, but the grid item has the prop isDraggable: true
, the item will be draggable, even if the item is marked static: true
.
{
// A string corresponding to the component key
i: string,
// These are all in grid units, not pixels
x: number,
y: number,
w: number,
h: number,
minW: ?number = 0,
maxW: ?number = Infinity,
minH: ?number = 0,
maxH: ?number = Infinity,
// If true, equal to `isDraggable: false, isResizable: false`.
static: ?boolean = false,
// If false, will not be draggable. Overrides `static`.
isDraggable: ?boolean = true,
// If false, will not be resizable. Overrides `static`.
isResizable: ?boolean = true,
// By default, a handle is only shown on the bottom-right (southeast) corner.
// Note that resizing from the top or left is generally not intuitive.
resizeHandles?: ?Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
// If true and draggable, item will be moved only within grid.
isBounded: ?boolean = false
}
Performance
<ReactGridLayout>
has an optimized shouldComponentUpdate
implementation, but it relies on the user memoizing the children
array:
// lib/ReactGridLayout.jsx
// ...
shouldComponentUpdate(nextProps: Props, nextState: State) {
return (
// NOTE: this is almost always unequal. Therefore the only way to get better performance
// from SCU is if the user intentionally memoizes children. If they do, and they can
// handle changes properly, performance will increase.
this.props.children !== nextProps.children ||
!fastRGLPropsEqual(this.props, nextProps, isEqual) ||
!isEqual(this.state.activeDrag, nextState.activeDrag)
);
}
// ...
If you memoize your children, you can take advantage of this, and reap faster rerenders. For example:
function MyGrid(props) {
const children = React.useMemo(() => {
return new Array(props.count).fill(undefined).map((val, idx) => {
return <div key={idx} data-grid={{x: idx, y: 1, w: 1, h: 1}} />;
});
}, [props.count]);
return <ReactGridLayout cols={12}>{children}</ReactGridLayout>;
}
Because the children
prop doesn't change between rerenders, updates to <MyGrid>
won't result in new renders, improving performance.
Custom Child Components and Draggable Handles
If you use React Components as grid children, they need to do a few things:
- Forward refs to an underlying DOM node, and
- Forward
style
andclassName
to that same DOM node.
For example:
const CustomGridItemComponent = React.forwardRef(({style, className, ...props}, ref) => {
return (
<div style={{ /* styles */, ...style}} className={className} ref={ref}>
{/* Some other content */}
</div>
);
}
The same is true of custom elements as draggable handles using the draggableHandle
prop. This is so that the underlying react-draggable
library can get a reference to the DOM node underneath, manipulate positioning via style
, and set classes.
Contribute
If you have a feature request, please add it as an issue or make a pull request.
If you have a bug to report, please reproduce the bug in CodeSandbox to help us easily isolate it.
TODO List
- [x] Basic grid layout
- [x] Fluid grid layout
- [x] Grid packing
- [x] Draggable grid items
- [x] Live grid packing while dragging
- [x] Resizable grid items
- [x] Layouts per responsive breakpoint
- [x] Define grid attributes on children themselves (
data-grid
key) - [x] Static elements
- [x] Persistent id per item for predictable localstorage restores, even when # items changes
- [x] Min/max w/h per item
- [ ] Resizable handles on other corners
- [ ] Configurable w/h per breakpoint