パッケージの詳細

react-grid-layout

STRML5.7mMIT2.0.0

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

react, grid, drag, draggable

readme

React-Grid-Layout

npm package npm downloads

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.

BitMEX UI

GIF from production usage on BitMEX.com

[Demo | Changelog | CodeSandbox Editable demo]

Table of Contents

What's New in v2

Version 2 is a complete TypeScript rewrite with a modernized API:

  • Full TypeScript support - First-class types, no more @types/react-grid-layout
  • React Hooks - New useContainerWidth, useGridLayout, and useResponsiveLayout hooks
  • Composable Configuration - Group related props into focused interfaces:
    • gridConfig - cols, rowHeight, margin, padding
    • dragConfig - enable, handle, cancel, bounded
    • resizeConfig - enable, handles
    • positionStrategy - transform vs absolute positioning
    • compactor - vertical, horizontal, or custom algorithms
  • Modular architecture - Import only what you need:
    • react-grid-layout - React components and hooks (v2 API)
    • react-grid-layout/core - Pure layout algorithms (framework-agnostic)
    • react-grid-layout/legacy - v1 flat props API for migration
    • react-grid-layout/extras - Optional components like GridBackground
  • Smaller bundle - Tree-shakeable ESM and CJS builds

Breaking Changes

See the RFC for detailed migration examples.

Change Description
width prop required Use useContainerWidth hook or provide your own measurement
onDragStart threshold Now fires after 3px movement, not on mousedown. Use onMouseDown for immediate response
Immutable callbacks Callback parameters are read-only. Use onLayoutChange or constraints instead of mutation
data-grid in legacy only v2 requires explicit layout prop. Use legacy wrapper for data-grid
Fast compaction O(n log n) algorithm may differ in edge cases. Use compact() from /core for exact v1 behavior
UMD bundle removed Use a bundler (Vite, webpack, esbuild)
verticalCompact removed Use compactType={null} or compactor={noCompactor}

Migrating from v1

Quick migration - change your import to use the legacy wrapper:

- import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout';
+ import GridLayout, { Responsive, WidthProvider } from 'react-grid-layout/legacy';

This provides 100% API compatibility with v1.

Full migration - adopt the v2 API for new features and better tree-shaking:

import ReactGridLayout, { useContainerWidth, verticalCompactor } from 'react-grid-layout';

function MyGrid() {
  const { width, containerRef, mounted } = useContainerWidth();

  return (
    <div ref={containerRef}>
      {mounted && (
        <ReactGridLayout
          width={width}
          layout={layout}
          gridConfig={{ cols: 12, rowHeight: 30 }}
          dragConfig={{ enabled: true, handle: '.handle' }}
          compactor={verticalCompactor}
        >
          {children}
        </ReactGridLayout>
      )}
    </div>
  );
}
Use Case Recommendation
Existing v1 codebase react-grid-layout/legacy
New project v2 API with hooks
Custom compaction v2 with custom Compactor
SSR v2 with measureBeforeMount: true

Demos

  1. Showcase
  2. Basic
  3. No Dragging/Resizing (Layout Only)
  4. Messy Layout Autocorrect
  5. Layout Defined on Children
  6. Static Elements
  7. Adding/Removing Elements
  8. Saving Layout to LocalStorage
  9. Saving a Responsive Layout to LocalStorage
  10. Minimum and Maximum Width/Height
  11. Dynamic Minimum and Maximum Width/Height
  12. No Vertical Compacting (Free Movement)
  13. Prevent Collision
  14. Error Case
  15. Toolbox
  16. Drag From Outside
  17. Bounded Layout
  18. Responsive Bootstrap-style Layout
  19. Scaled Containers
  20. Allow Overlap
  21. All Resizable Handles
  22. Single Row Horizontal

Projects Using React-Grid-Layout

Know of others? Create a PR to let me know!

Features

  • 100% React - no jQuery
  • Full TypeScript support
  • 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
  • Compatibility with <React.StrictMode>
Version Compatibility
>= 2.0.0 React 18+, TypeScript
>= 0.17.0 React 16 & 17

Installation

npm install react-grid-layout

Include the stylesheets in your application:

import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";

Or link them directly:

<link rel="stylesheet" href="/node_modules/react-grid-layout/css/styles.css" />
<link rel="stylesheet" href="/node_modules/react-resizable/css/styles.css" />

Quick Start

import ReactGridLayout, { useContainerWidth } from "react-grid-layout";
import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";

function MyGrid() {
  const { width, containerRef, mounted } = useContainerWidth();

  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 (
    <div ref={containerRef}>
      {mounted && (
        <ReactGridLayout
          layout={layout}
          width={width}
          gridConfig={{ cols: 12, rowHeight: 30 }}
        >
          <div key="a">a</div>
          <div key="b">b</div>
          <div key="c">c</div>
        </ReactGridLayout>
      )}
    </div>
  );
}

You can also define layout on children using data-grid:

<ReactGridLayout width={width} gridConfig={{ cols: 12, rowHeight: 30 }}>
  <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 }}>
    b
  </div>
  <div key="c" data-grid={{ x: 4, y: 0, w: 1, h: 2 }}>
    c
  </div>
</ReactGridLayout>

Responsive Usage

Use Responsive for automatic breakpoint handling:

import { Responsive, useContainerWidth } from "react-grid-layout";

function MyResponsiveGrid() {
  const { width, containerRef, mounted } = useContainerWidth();

  const layouts = {
    lg: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }],
    md: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }]
  };

  return (
    <div ref={containerRef}>
      {mounted && (
        <Responsive
          layouts={layouts}
          breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
          cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
          width={width}
        >
          <div key="1">1</div>
          <div key="2">2</div>
          <div key="3">3</div>
        </Responsive>
      )}
    </div>
  );
}

Providing Grid Width

The width prop is required. You have several options:

Option 1: useContainerWidth Hook (Recommended)

import ReactGridLayout, { useContainerWidth } from "react-grid-layout";

function MyGrid() {
  const { width, containerRef, mounted } = useContainerWidth();

  return (
    <div ref={containerRef}>
      {mounted && <ReactGridLayout width={width}>...</ReactGridLayout>}
    </div>
  );
}

Option 2: Fixed Width

<ReactGridLayout width={1200}>...</ReactGridLayout>

Option 3: CSS Container Queries or ResizeObserver

Use any width measurement library like react-sizeme or your own ResizeObserver implementation.

Option 4: Legacy WidthProvider HOC

For backwards compatibility, you can still use WidthProvider:

import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";

const GridLayoutWithWidth = WidthProvider(ReactGridLayout);

function MyGrid() {
  return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
}

Hooks API

The v2 API provides three hooks for different use cases. Choose based on your needs:

Hook Use When
useContainerWidth You need responsive width measurement (most common)
useGridLayout You're building a custom grid component or need direct state control
useResponsiveLayout You're building a custom responsive grid with breakpoint logic

useContainerWidth

Observes container width using ResizeObserver and provides reactive width updates. This is the recommended way to provide width to the grid.

Why use it instead of WidthProvider?

  • Hooks are more composable and easier to test
  • No HOC wrapper means simpler component tree
  • Explicit control over when to render (via mounted)
  • Works better with SSR
import { useContainerWidth } from "react-grid-layout";

function MyGrid() {
  const { width, containerRef, mounted, measureWidth } = useContainerWidth({
    measureBeforeMount: false, // Set true for SSR
    initialWidth: 1280 // Width before first measurement
  });

  return (
    <div ref={containerRef}>{mounted && <ReactGridLayout width={width} />}</div>
  );
}

Type Definitions:

interface UseContainerWidthOptions {
  /** Delay render until width is measured. Useful for SSR. Default: false */
  measureBeforeMount?: boolean;
  /** Initial width before measurement. Default: 1280 */
  initialWidth?: number;
}

interface UseContainerWidthResult {
  /** Current container width in pixels */
  width: number;
  /** Whether the container has been measured at least once */
  mounted: boolean;
  /** Ref to attach to the container element */
  containerRef: RefObject<HTMLDivElement | null>;
  /** Manually trigger a width measurement */
  measureWidth: () => void;
}

useGridLayout

Core layout state management hook. Use this when you need direct control over drag/resize/drop state, or when building a custom grid component.

Why use it instead of the component?

  • Full control over layout state and updates
  • Access to drag/resize/drop state for custom UIs
  • Can integrate with external state management
  • Build headless grid implementations
import { useGridLayout } from "react-grid-layout";

function CustomGrid({ initialLayout }) {
  const {
    layout,
    setLayout,
    dragState,
    resizeState,
    onDragStart,
    onDrag,
    onDragStop,
    onResizeStart,
    onResize,
    onResizeStop,
    containerHeight,
    isInteracting,
    compactor
  } = useGridLayout({
    layout: initialLayout,
    cols: 12,
    compactType: "vertical",
    allowOverlap: false,
    preventCollision: false,
    onLayoutChange: newLayout => console.log("Layout changed:", newLayout)
  });

  // Access drag state for custom placeholder rendering
  const placeholder = dragState.activeDrag;

  // Check if any interaction is happening
  if (isInteracting) {
    // Disable other UI during drag/resize
  }

  return (
    <div style={{ height: containerHeight * rowHeight }}>
      {layout.map(item => (
        <div
          key={item.i}
          onMouseDown={() => onDragStart(item.i, item.x, item.y)}
        >
          {item.i}
        </div>
      ))}
      {placeholder && <div className="placeholder" />}
    </div>
  );
}

Type Definitions:

interface UseGridLayoutOptions {
  /** Initial layout */
  layout: Layout;
  /** Number of columns */
  cols: number;
  /** Compaction type: 'vertical', 'horizontal', or null */
  compactType?: CompactType;
  /** Allow items to overlap */
  allowOverlap?: boolean;
  /** Prevent collisions when moving items */
  preventCollision?: boolean;
  /** Called when layout changes */
  onLayoutChange?: (layout: Layout) => void;
}

interface UseGridLayoutResult {
  /** Current layout */
  layout: Layout;
  /** Set layout directly */
  setLayout: (layout: Layout) => void;
  /** Current drag state (activeDrag, oldDragItem, oldLayout) */
  dragState: DragState;
  /** Current resize state (resizing, oldResizeItem, oldLayout) */
  resizeState: ResizeState;
  /** Current drop state (droppingDOMNode, droppingPosition) */
  dropState: DropState;
  /** Start dragging an item */
  onDragStart: (itemId: string, x: number, y: number) => LayoutItem | null;
  /** Update drag position */
  onDrag: (itemId: string, x: number, y: number) => void;
  /** Stop dragging */
  onDragStop: (itemId: string, x: number, y: number) => void;
  /** Start resizing an item */
  onResizeStart: (itemId: string) => LayoutItem | null;
  /** Update resize dimensions */
  onResize: (
    itemId: string,
    w: number,
    h: number,
    x?: number,
    y?: number
  ) => void;
  /** Stop resizing */
  onResizeStop: (itemId: string, w: number, h: number) => void;
  /** Handle external drag over */
  onDropDragOver: (
    droppingItem: LayoutItem,
    position: DroppingPosition
  ) => void;
  /** Handle external drag leave */
  onDropDragLeave: () => void;
  /** Complete external drop */
  onDrop: (droppingItem: LayoutItem) => void;
  /** Container height in grid rows */
  containerHeight: number;
  /** Whether any drag/resize/drop is active */
  isInteracting: boolean;
  /** The compactor being used */
  compactor: Compactor;
}

useResponsiveLayout

Manages responsive breakpoints and generates layouts for different screen sizes. Use this when building a custom responsive grid.

Why use it instead of the Responsive component?

  • Direct access to current breakpoint
  • Control over layout generation for new breakpoints
  • Can update layouts for specific breakpoints
  • Build custom breakpoint UIs
import { useContainerWidth, useResponsiveLayout } from "react-grid-layout";

function CustomResponsiveGrid() {
  const { width, containerRef, mounted } = useContainerWidth();

  const {
    layout, // Current layout for active breakpoint
    layouts, // All layouts by breakpoint
    breakpoint, // Current active breakpoint ('lg', 'md', etc.)
    cols, // Column count for current breakpoint
    setLayoutForBreakpoint,
    setLayouts,
    sortedBreakpoints
  } = useResponsiveLayout({
    width,
    breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
    cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
    layouts: {
      lg: [{ i: "1", x: 0, y: 0, w: 2, h: 2 }],
      md: [{ i: "1", x: 0, y: 0, w: 3, h: 2 }]
    },
    compactType: "vertical",
    onBreakpointChange: (bp, cols) =>
      console.log(`Now at ${bp} (${cols} cols)`),
    onLayoutChange: (layout, allLayouts) => saveToServer(allLayouts)
  });

  // Show current breakpoint in UI
  return (
    <div ref={containerRef}>
      <div>
        Current breakpoint: {breakpoint} ({cols} columns)
      </div>
      {mounted && (
        <GridLayout width={width} cols={cols} layout={layout}>
          {/* children */}
        </GridLayout>
      )}
    </div>
  );
}

Type Definitions:

interface UseResponsiveLayoutOptions<B extends string = DefaultBreakpoints> {
  /** Current container width */
  width: number;
  /** Breakpoint definitions (name → min-width). Default: {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0} */
  breakpoints?: Record<B, number>;
  /** Column counts per breakpoint. Default: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2} */
  cols?: Record<B, number>;
  /** Layouts for each breakpoint */
  layouts?: Partial<Record<B, Layout>>;
  /** Compaction type */
  compactType?: "vertical" | "horizontal" | null;
  /** Called when breakpoint changes */
  onBreakpointChange?: (newBreakpoint: B, cols: number) => void;
  /** Called when layout changes */
  onLayoutChange?: (layout: Layout, layouts: Record<B, Layout>) => void;
  /** Called when width changes */
  onWidthChange?: (
    width: number,
    margin: [number, number],
    cols: number,
    padding: [number, number] | null
  ) => void;
}

interface UseResponsiveLayoutResult<B extends string = DefaultBreakpoints> {
  /** Current layout for the active breakpoint */
  layout: Layout;
  /** All layouts by breakpoint */
  layouts: Partial<Record<B, Layout>>;
  /** Current active breakpoint */
  breakpoint: B;
  /** Column count for the current breakpoint */
  cols: number;
  /** Update layout for a specific breakpoint */
  setLayoutForBreakpoint: (breakpoint: B, layout: Layout) => void;
  /** Update all layouts */
  setLayouts: (layouts: Partial<Record<B, Layout>>) => void;
  /** Sorted array of breakpoint names (smallest to largest) */
  sortedBreakpoints: B[];
}

type DefaultBreakpoints = "lg" | "md" | "sm" | "xs" | "xxs";

API Reference

ReactGridLayout Props

The v2 API uses composable configuration interfaces for cleaner prop organization:

interface ReactGridLayoutProps {
  // Required
  children: React.ReactNode;
  width: number; // Container width in pixels

  // Configuration interfaces (see below for details)
  gridConfig?: Partial<GridConfig>; // Grid measurement settings
  dragConfig?: Partial<DragConfig>; // Drag behavior settings
  resizeConfig?: Partial<ResizeConfig>; // Resize behavior settings
  dropConfig?: Partial<DropConfig>; // External drop settings
  positionStrategy?: PositionStrategy; // CSS positioning strategy
  compactor?: Compactor; // Layout compaction strategy

  // Layout data
  layout?: Layout; // Layout definition
  droppingItem?: LayoutItem; // Item configuration when dropping from outside

  // Container
  autoSize?: boolean; // Auto-size container height (default: true)
  className?: string;
  style?: React.CSSProperties;
  innerRef?: React.Ref<HTMLDivElement>;

  // Callbacks
  onLayoutChange?: (layout: Layout) => void;
  onDragStart?: EventCallback;
  onDrag?: EventCallback;
  onDragStop?: EventCallback;
  onResizeStart?: EventCallback;
  onResize?: EventCallback;
  onResizeStop?: EventCallback;
  onDrop?: (layout: Layout, item: LayoutItem | undefined, e: Event) => void;
  onDropDragOver?: (e: DragEvent) => { w?: number; h?: number } | false | void;
}

GridConfig

Grid measurement configuration:

interface GridConfig {
  cols: number; // Number of columns (default: 12)
  rowHeight: number; // Row height in pixels (default: 150)
  margin: [number, number]; // [x, y] margin between items (default: [10, 10])
  containerPadding: [number, number] | null; // Container padding (default: null, uses margin)
  maxRows: number; // Maximum rows (default: Infinity)
}

DragConfig

Drag behavior configuration:

interface DragConfig {
  enabled: boolean; // Enable dragging (default: true)
  bounded: boolean; // Keep items within container (default: false)
  handle?: string; // CSS selector for drag handle
  cancel?: string; // CSS selector to cancel dragging
  threshold: number; // Pixels to move before drag starts (default: 3)
}

ResizeConfig

Resize behavior configuration:

interface ResizeConfig {
  enabled: boolean; // Enable resizing (default: true)
  handles: ResizeHandleAxis[]; // Handle positions (default: ['se'])
  handleComponent?: React.ReactNode | ((axis, ref) => React.ReactNode);
}

DropConfig

External drop configuration:

interface DropConfig {
  enabled: boolean; // Allow external drops (default: false)
  defaultItem: { w: number; h: number }; // Default size (default: { w: 1, h: 1 })
  onDragOver?: (e: DragEvent) => { w?: number; h?: number } | false | void;
}

PositionStrategy

CSS positioning strategy. Built-in options:

import {
  transformStrategy, // Default: use CSS transforms
  absoluteStrategy, // Use top/left positioning
  createScaledStrategy // For scaled containers
} from "react-grid-layout/core";

// Example: scaled container
<div style={{ transform: 'scale(0.5)' }}>
  <ReactGridLayout positionStrategy={createScaledStrategy(0.5)} ... />
</div>

Compactor

Layout compaction strategy. Built-in options:

import {
  verticalCompactor, // Default: compact items upward
  horizontalCompactor, // Compact items leftward
  noCompactor, // No compaction (free positioning)
  getCompactor // Factory: getCompactor('vertical', allowOverlap, preventCollision)
} from "react-grid-layout/core";

ResponsiveGridLayout Props

Extends GridLayoutProps with responsive-specific props:

interface ResponsiveGridLayoutProps<B extends string = string> {
  // Responsive configuration
  breakpoint?: B; // Current breakpoint (auto-detected)
  breakpoints?: Record<B, number>; // Breakpoint definitions (default: {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0})
  cols?: Record<B, number>; // Columns per breakpoint (default: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2})
  layouts?: Record<B, Layout>; // Layouts per breakpoint

  // Can be fixed or per-breakpoint
  margin?: [number, number] | Partial<Record<B, [number, number]>>;
  containerPadding?:
    | [number, number]
    | Partial<Record<B, [number, number] | null>>
    | null;

  // Callbacks
  onBreakpointChange?: (newBreakpoint: B, cols: number) => void;
  onLayoutChange?: (layout: Layout, layouts: Record<B, Layout>) => void;
  onWidthChange?: (
    width: number,
    margin: [number, number],
    cols: number,
    padding: [number, number] | null
  ) => void;
}

Layout Item

interface LayoutItem {
  i: string; // Unique identifier (must match child key)
  x: number; // X position in grid units
  y: number; // Y position in grid units
  w: number; // Width in grid units
  h: number; // Height in grid units
  minW?: number; // Minimum width (default: 0)
  maxW?: number; // Maximum width (default: Infinity)
  minH?: number; // Minimum height (default: 0)
  maxH?: number; // Maximum height (default: Infinity)
  static?: boolean; // If true, not draggable or resizable
  isDraggable?: boolean; // Override grid isDraggable
  isResizable?: boolean; // Override grid isResizable
  isBounded?: boolean; // Override grid isBounded
  resizeHandles?: Array<"s" | "w" | "e" | "n" | "sw" | "nw" | "se" | "ne">;
}

Core Utilities

Import pure layout functions from react-grid-layout/core:

import {
  compact,
  moveElement,
  collides,
  getFirstCollision,
  validateLayout
  // ... and more
} from "react-grid-layout/core";

Extending: Custom Compactors & Position Strategies

Creating a Custom Compactor

Compactors control how items are arranged after drag/resize. Create your own for custom layouts like masonry, gravity, or shelf-packing.

The Compactor Interface:

interface Compactor {
  /** Identifies the compaction type */
  type: "vertical" | "horizontal" | null | string;

  /** Whether this compactor allows overlapping items */
  allowOverlap: boolean;

  /** Prevent items from moving when another item is dragged into them */
  preventCollision?: boolean;

  /**
   * Compact the entire layout.
   * Called after any layout change to fill gaps.
   *
   * @param layout - Array of layout items (clone before mutating!)
   * @param cols - Number of grid columns
   * @returns New compacted layout
   */
  compact(layout: Layout, cols: number): Layout;

  /**
   * Handle moving an item.
   * Called during drag to preview the new position.
   *
   * @param layout - Current layout
   * @param item - Item being moved
   * @param x - New X position in grid units
   * @param y - New Y position in grid units
   * @param cols - Number of grid columns
   * @returns Updated layout with item at new position
   */
  onMove(
    layout: Layout,
    item: LayoutItem,
    x: number,
    y: number,
    cols: number
  ): Layout;
}

Example: Gravity Compactor (items fall to bottom)

import { cloneLayout, cloneLayoutItem, getStatics, bottom } from "react-grid-layout/core";

const gravityCompactor: Compactor = {
  type: "gravity",
  allowOverlap: false,

  compact(layout, cols) {
    const statics = getStatics(layout);
    const maxY = 100; // arbitrary max height
    const out = [];

    // Sort by Y descending (process bottom items first)
    const sorted = [...layout].sort((a, b) => b.y - a.y);

    for (const item of sorted) {
      const l = cloneLayoutItem(item);

      if (!l.static) {
        // Move down as far as possible
        while (l.y < maxY && !collides(l, statics)) {
          l.y++;
        }
        l.y--; // Back up one
      }

      out.push(l);
    }

    return out;
  },

  onMove(layout, item, x, y, cols) {
    const newLayout = cloneLayout(layout);
    const movedItem = newLayout.find(l => l.i === item.i);
    if (movedItem) {
      movedItem.x = x;
      movedItem.y = y;
      movedItem.moved = true;
    }
    return newLayout;
  }
};

// Usage
<GridLayout compactor={gravityCompactor} />

Example: Single Row Compactor (horizontal shelf)

const singleRowCompactor: Compactor = {
  type: "shelf",
  allowOverlap: false,

  compact(layout, cols) {
    let x = 0;
    const out = [];

    // Sort by original X position
    const sorted = [...layout].sort((a, b) => a.x - b.x);

    for (const item of sorted) {
      const l = cloneLayoutItem(item);
      if (!l.static) {
        l.x = x;
        l.y = 0; // All items on row 0
        x += l.w;

        // Wrap to next row if overflow
        if (x > cols) {
          l.x = 0;
          x = l.w;
        }
      }
      out.push(l);
    }

    return out;
  },

  onMove(layout, item, x, y, cols) {
    // Same as default - just update position
    const newLayout = cloneLayout(layout);
    const movedItem = newLayout.find(l => l.i === item.i);
    if (movedItem) {
      movedItem.x = x;
      movedItem.y = 0; // Force row 0
      movedItem.moved = true;
    }
    return newLayout;
  }
};

Using Helper Functions:

The core module exports helpers for building compactors:

import {
  resolveCompactionCollision, // Move items to resolve overlaps
  compactItemVertical, // Compact one item upward
  compactItemHorizontal, // Compact one item leftward
  getFirstCollision, // Find first collision
  collides, // Check if two items collide
  getStatics, // Get static items from layout
  cloneLayout, // Clone layout array
  cloneLayoutItem // Clone single item
} from "react-grid-layout/core";

Creating a Custom Position Strategy

Position strategies control how items are positioned via CSS. Create custom strategies for special transform handling.

The PositionStrategy Interface:

interface PositionStrategy {
  /** Type identifier */
  type: "transform" | "absolute" | string;

  /** Scale factor for coordinate calculations */
  scale: number;

  /**
   * Generate CSS styles for positioning an item.
   *
   * @param pos - Position with top, left, width, height in pixels
   * @returns CSS properties object
   */
  calcStyle(pos: Position): React.CSSProperties;

  /**
   * Calculate drag position from mouse coordinates.
   * Used during drag to convert screen coords to grid coords.
   *
   * @param clientX - Mouse X position
   * @param clientY - Mouse Y position
   * @param offsetX - Offset from item left edge
   * @param offsetY - Offset from item top edge
   * @returns Calculated left/top position
   */
  calcDragPosition(
    clientX: number,
    clientY: number,
    offsetX: number,
    offsetY: number
  ): { left: number; top: number };
}

Example: Rotated Container Strategy

const createRotatedStrategy = (angleDegrees: number): PositionStrategy => {
  const angleRad = (angleDegrees * Math.PI) / 180;
  const cos = Math.cos(angleRad);
  const sin = Math.sin(angleRad);

  return {
    type: "rotated",
    scale: 1,

    calcStyle(pos) {
      // Apply rotation to position
      const rotatedX = pos.left * cos - pos.top * sin;
      const rotatedY = pos.left * sin + pos.top * cos;

      return {
        transform: `translate(${rotatedX}px, ${rotatedY}px)`,
        width: `${pos.width}px`,
        height: `${pos.height}px`,
        position: "absolute"
      };
    },

    calcDragPosition(clientX, clientY, offsetX, offsetY) {
      // Reverse the rotation for drag calculations
      const x = clientX - offsetX;
      const y = clientY - offsetY;

      return {
        left: x * cos + y * sin,
        top: -x * sin + y * cos
      };
    }
  };
};

// Usage: grid inside a rotated container
<div style={{ transform: 'rotate(45deg)' }}>
  <GridLayout positionStrategy={createRotatedStrategy(45)} />
</div>

Example: 3D Perspective Strategy

const create3DStrategy = (
  perspective: number,
  rotateX: number
): PositionStrategy => ({
  type: "3d",
  scale: 1,

  calcStyle(pos) {
    return {
      transform: `
        perspective(${perspective}px)
        rotateX(${rotateX}deg)
        translate3d(${pos.left}px, ${pos.top}px, 0)
      `,
      width: `${pos.width}px`,
      height: `${pos.height}px`,
      position: "absolute",
      transformStyle: "preserve-3d"
    };
  },

  calcDragPosition(clientX, clientY, offsetX, offsetY) {
    // Adjust for perspective foreshortening
    const perspectiveFactor = 1 + clientY / perspective;
    return {
      left: (clientX - offsetX) / perspectiveFactor,
      top: (clientY - offsetY) / perspectiveFactor
    };
  }
});

Extras

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.

GridBackground

Renders an SVG grid background that aligns with GridLayout cells. Use this to visualize the grid structure behind your layout.

Based on PR #2175 by @nicosayer.

import { GridBackground } from "react-grid-layout/extras";
import ReactGridLayout, { useContainerWidth } from "react-grid-layout";

function MyGrid() {
  const { width, containerRef, mounted } = useContainerWidth();

  return (
    <div ref={containerRef} style={{ position: "relative" }}>
      {mounted && (
        <>
          <GridBackground
            width={width}
            cols={12}
            rowHeight={30}
            margin={[10, 10]}
            rows={10}
            color="#f0f0f0"
            borderRadius={4}
          />
          <ReactGridLayout
            width={width}
            gridConfig={{ cols: 12, rowHeight: 30, margin: [10, 10] }}
          >
            {children}
          </ReactGridLayout>
        </>
      )}
    </div>
  );
}

Props:

interface GridBackgroundProps {
  // Required - must match your GridLayout config
  width: number; // Container width
  cols: number; // Number of columns
  rowHeight: number; // Row height in pixels

  // Optional
  margin?: [number, number]; // Gap between cells (default: [10, 10])
  containerPadding?: [number, number] | null; // Container padding (default: uses margin)
  rows?: number | "auto"; // Number of rows to display (default: 10)
  height?: number; // Used when rows="auto" to calculate row count
  color?: string; // Cell background color (default: "#e0e0e0")
  borderRadius?: number; // Cell border radius (default: 4)
  className?: string; // Additional CSS class
  style?: React.CSSProperties; // Additional inline styles
}

calcGridCellDimensions (Core Utility)

For building custom grid overlays or backgrounds, use the calcGridCellDimensions utility from react-grid-layout/core:

import { calcGridCellDimensions } from "react-grid-layout/core";

const dims = calcGridCellDimensions({
  width: 1200,
  cols: 12,
  rowHeight: 30,
  margin: [10, 10],
  containerPadding: [20, 20]
});

// dims = {
//   cellWidth: 88.33,  // Width of each cell
//   cellHeight: 30,     // Height of each cell (= rowHeight)
//   offsetX: 20,        // Left padding
//   offsetY: 20,        // Top padding
//   gapX: 10,           // Horizontal gap between cells
//   gapY: 10,           // Vertical gap between cells
//   cols: 12,           // Column count
//   containerWidth: 1200
// }

This is useful for building custom visualizations, snap-to-grid functionality, or integrating with canvas/WebGL renderers.

Performance

Memoize Children

The grid compares children by reference. Memoize them for better performance:

function MyGrid({ count, width }) {
  const children = useMemo(() => {
    return Array.from({ length: count }, (_, i) => (
      <div
        key={i}
        data-grid={{ x: i % 12, y: Math.floor(i / 12), w: 1, h: 1 }}
      />
    ));
  }, [count]);

  return (
    <ReactGridLayout width={width} gridConfig={{ cols: 12 }}>
      {children}
    </ReactGridLayout>
  );
}

Avoid Creating Components in Render (Legacy WidthProvider)

If using the legacy WidthProvider HOC, don't create the component during render:

import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";

// Bad - creates new component every render
function MyGrid() {
  const GridLayoutWithWidth = WidthProvider(ReactGridLayout);
  return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
}

// Good - create once outside or with useMemo
const GridLayoutWithWidth = WidthProvider(ReactGridLayout);

function MyGrid() {
  return <GridLayoutWithWidth>...</GridLayoutWithWidth>;
}

With the v2 API, use useContainerWidth hook instead to avoid this issue entirely.

Custom Child Components

Grid children must forward refs and certain props:

const CustomItem = forwardRef<HTMLDivElement, CustomItemProps>(
  (
    {
      style,
      className,
      onMouseDown,
      onMouseUp,
      onTouchEnd,
      children,
      ...props
    },
    ref
  ) => {
    return (
      <div
        ref={ref}
        style={style}
        className={className}
        onMouseDown={onMouseDown}
        onMouseUp={onMouseUp}
        onTouchEnd={onTouchEnd}
      >
        {children}
      </div>
    );
  }
);

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.

更新履歴

Changelog

2.0.0 (Dec 9, 2025)

Version 2 is a complete TypeScript rewrite with a modernized hooks-based API. See the RFC for the full design document.

Highlights

  • Full TypeScript support - First-class types, no more @types/react-grid-layout needed
  • React Hooks API - New useContainerWidth, useGridLayout, and useResponsiveLayout hooks
  • Composable Configuration - Group related props into focused interfaces (gridConfig, dragConfig, resizeConfig, positionStrategy, compactor)
  • Modular Architecture - Tree-shakeable ESM and CJS builds with multiple entry points
  • Legacy Compatibility - 100% backwards compatible via react-grid-layout/legacy

Breaking Changes

See the migration section in the README for detailed examples.

width Prop Required

The grid no longer auto-measures width. Use the new useContainerWidth hook:

import ReactGridLayout, { useContainerWidth } from "react-grid-layout";

function MyGrid() {
  const { width, containerRef, mounted } = useContainerWidth();
  return (
    <div ref={containerRef}>
      {mounted && <ReactGridLayout width={width} ... />}
    </div>
  );
}

Or use the legacy wrapper for backwards compatibility:

import ReactGridLayout, { WidthProvider } from "react-grid-layout/legacy";
const GridLayoutWithWidth = WidthProvider(ReactGridLayout);

onDragStart Threshold

onDragStart now fires after 3px of mouse movement, not on mousedown. This fixes #1341 and #1401. Use onMouseDown directly on grid items if you need immediate response.

Immutable Callback Parameters

Callback parameters (layoutItem, placeholder) are now read-only. Mutating them in onResize/onDrag callbacks no longer works. Use onLayoutChange or item constraints (minW, maxW, etc.) instead.

data-grid Prop in Legacy Only

The v2 API requires explicit layout prop. The data-grid pattern is only available via the legacy wrapper (react-grid-layout/legacy).

Fast Compaction Algorithm

The default compaction algorithm is now O(n log n) instead of O(n²). It produces identical results for most layouts but may differ in edge cases. Use the compact() function from react-grid-layout/core if you need exact v1 behavior.

Other Breaking Changes

  • UMD bundle removed - Use a bundler (Vite, webpack, esbuild)
  • verticalCompact prop removed - Use compactType={null} or compactor={noCompactor}
  • React 18+ required - React 16/17 support is available only via the legacy wrapper

New Features

Entry Points

// v2 API (recommended)
import ReactGridLayout, {
  Responsive,
  useContainerWidth
} from "react-grid-layout";

// Core utilities (framework-agnostic, no React)
import { compact, moveElement, collides } from "react-grid-layout/core";

// Legacy v1 API (100% backwards compatible)
import ReactGridLayout, {
  WidthProvider,
  Responsive
} from "react-grid-layout/legacy";

// Optional extras
import { GridBackground } from "react-grid-layout/extras";

Hooks

  • useContainerWidth() - Reactive container width measurement with ResizeObserver
  • useGridLayout() - Core layout state management for custom implementations
  • useResponsiveLayout() - Responsive breakpoint management

Composable Configuration Interfaces

<ReactGridLayout
  width={width}
  layout={layout}
  gridConfig={{ cols: 12, rowHeight: 30, margin: [10, 10] }}
  dragConfig={{ enabled: true, handle: ".handle", bounded: true }}
  resizeConfig={{ enabled: true, handles: ["se", "sw"] }}
  positionStrategy={transformStrategy}
  compactor={verticalCompactor}
/>

Pluggable Compactors

Create custom compaction algorithms by implementing the Compactor interface:

import {
  verticalCompactor,
  horizontalCompactor,
  noCompactor
} from "react-grid-layout/core";

// Or create custom compactors
const myCompactor: Compactor = {
  type: "custom",
  allowOverlap: false,
  compact(layout, cols) {
    /* ... */
  },
  onMove(layout, item, x, y, cols) {
    /* ... */
  }
};

Position Strategies

Control CSS positioning with the PositionStrategy interface:

import { transformStrategy, absoluteStrategy, createScaledStrategy } from "react-grid-layout/core";

// For scaled containers
<div style={{ transform: "scale(0.5)" }}>
  <ReactGridLayout positionStrategy={createScaledStrategy(0.5)} />
</div>

GridBackground Component

New optional component to visualize the grid structure:

import { GridBackground } from "react-grid-layout/extras";

<GridBackground
  width={width}
  cols={12}
  rowHeight={30}
  rows={10}
  color="#f0f0f0"
/>;

Core Utilities

New calcGridCellDimensions utility for building custom grid overlays:

import { calcGridCellDimensions } from "react-grid-layout/core";

const dims = calcGridCellDimensions({
  width: 1200,
  cols: 12,
  rowHeight: 30,
  margin: [10, 10]
});
// { cellWidth, cellHeight, offsetX, offsetY, gapX, gapY, cols, containerWidth }

React 18 Compatibility

  • Full React 18 support. The library now works seamlessly with React 18's automatic batching without any flushSync warnings.
  • Removed flushSync usage from drag and resize handlers.

Bugfixes

  • Fixed operator precedence bug in moveDroppingItem where shouldDrag would incorrectly evaluate to true when only the top position changed.
  • Fixed resize position calculation when node is falsy in onResizeHandler.

Internal Changes

  • Complete TypeScript rewrite - All code is now TypeScript with full type coverage
  • Migrated from Flow to TypeScript - Removed all Flow annotations
  • Modular package structure - src/core/ (pure TS), src/react/ (React bindings), src/legacy/ (v1 compatibility)
  • Build system - Now uses tsup for ESM, CJS, and declaration file generation
  • Migrated test suite from Enzyme to React Testing Library
  • ESLint 9 with flat config
  • Removed lib/ folder and Flow configuration
  • Removed snapshot tests in favor of behavioral tests

Migration Guide

Quick migration (no code changes):

- import GridLayout from 'react-grid-layout';
+ import GridLayout from 'react-grid-layout/legacy';

Full migration (recommended for new features):

  1. Replace WidthProvider HOC with useContainerWidth hook
  2. Replace data-grid props with explicit layout prop
  3. Use configuration interfaces (gridConfig, dragConfig, etc.) for cleaner props
  4. Update any code that mutates callback parameters to use onLayoutChange instead

See the README for detailed examples

1.5.3 (Dec 5, 2025)

  • Fix collision detection y-coordinate offset. #2173
  • Memoize bottom computation in compact for performance. #2115
  • Make b param in compactItem optional. #2165
  • Fix example animations and rework example styles.
  • Various devDependency updates and security fixes. #2179

1.5.2 (Jun 25, 2025)

  • Fix calcXY when isBounded=true moving items incorrectly. Likely related to #2059. Thanks @wanpan11. #2102

1.5.1 (Mar 11, 2025)

  • Fix for React 18: wrap state calls in flushSync. Thanks @ashharrison90. #2043

1.5.0 (Oct 9, 2024)

  • Fix calcXY moving grid items slightly above and to the left of where they should be. Thanks @MaxMusing. #2059
  • Change onBreakpointChange/onLayoutChange event order. onBreakpointChange now fires first. This should make managing responsive layouts easier, as you can set the current breakpoint in storage, then save the new layout to it.

1.4.4 (Nov 28, 2023)

Bugfixes

  • Fix position logic when draggable item is dragged into the grid. We no longer use the deprecated / non-standard e.nativeEvent.layer{X,Y} properties. #1915
  • Fix drag values according to containerPadding. Previously, when dragging an item, the intuited position within the grid was not modified by containerPadding, causing it to off by that value. On most grids, this is only set to [10, 10], so this may not have been noticeable, but for higher values it was very obvious. Thanks @hywlss9. #1323
  • Various lint/dependency fixes.

1.4.3 (Nov 8, 2023)

Bugfixes

  • Set activeDrag in onDragStart. Fixes issues where, if no drag is performed, the onDragStop handler would error out and the drag would freeze. #1923
    • THis fixes some broader issues with React 18 but testing library support is still not complete.

1.4.2 (Sep 22, 2023)

Bugfixes

  • Resizing in every directionnow obeys preventCollision restrictions #1937

1.4.1 (Sep 12, 2023)

Bugfixes

  • Fixed bug where height/width could not be resized if h = 0 or w = 0 and 0 containerPadding. #1931
  • Revert fast-equals to @4. Fixes incompatibility with Create-React-App@5.

1.4.0 (Sep 11, 2023)

Hey, it's been a long time! Taking a year and a half off is a pretty "open-source" thing to do, thanks for bearing with me.

New Features

  • Grid items can now be resized left and up! Thanks to @ludovic and @dseif for all the hard work they did on this. #1917
    • To use, specify resizeHandles directions on your <GridItem>s. See the example for more on how to do this.
    • See also the demo.
  • <WidthProvider> now uses a ResizeObserver instead of hooking into the window's 'resize' event. #1839
    • This should not be breaking for any users but introduces a new dependency, resize-observer-polyfill. It will not be imported unless you use <WidthProvider>.

Bugfixes

  • Fixed horizontal compact not always moving grid elements as far left as possible. #1822
  • Fixed a bug when allowOverlap={true} and compactType={null}, where collisions would still be processed. #1782
  • Fixed onResizeStop and onDragStop callbacks not returning updated layout. #1613
  • An item will now rerender when data-grid props change. #718
  • Corrected draggableHandle configuration in static elements example #1826

Internal Changes

  • Various dependency upgrades and upgraded tests.
  • Removed long-deprecated _grid property.
  • Various doc updates.

1.3.4 (Feb 21, 2022)

Bugfixes

  • Add e.stopPropagation() on drag events to better support nested grids. Thanks @rogerfar #1494.

Internal Changes

  • Various dependency upgrades.

1.3.3 (Jan 24, 2022)

This was a quick release to improve package size and dependency use. Thanks @salvoravida #1655

Bugfixes

  • Removed coverage/ folder from npm package to save size
  • Moved eslint parser to devDependencies

1.3.2 (Jan 24, 2022)

Internal Changes

  • Package size reduced by ~30% by removing source in dist/ source maps.
  • Various tests added (thanks @imagineLife!)
  • New GitHub Actions flow for PRs

1.3.1 (Nov 29, 2021)

Bugfixes

  • Fix allowOverlap not firing onLayoutChange(). #1620
    • This was due to a short-circuiting of internal logic that did not properly clone the layout prop.

Internal Changes

  • Replace classnames with clsx for smaller package size. (#1543)

1.3.0 (Aug 27, 2021)

New Features

  • allowOverlap prop, when true, allows overlapping grid items. #1470
  • Add onDropDragOver callback. #1395
    • Use this callback to dynamically adjust the droppingItem based on what is being dragged over. Return w and h to adjust the item. It is then spread into the dropping placeholder.
    • This callback has the type:
      • onDragOver: (e: DragOverEvent) => { w: number, h: number } | false;
      • Return false to short-circuit the dragover.

Bugfixes

  • Remove sorting when compactType is null. #1474
  • Droppable fixes for Chrome behavior. #1442 #1448
  • Allow null children as a convenience so that inline expressions don't break the library. #1296
  • Various dependency upgrades.

Documentation

  • Add docs on using custom components as grid children.
  • Note required class on resizable handles for proper styling.

1.2.5 (May 10, 2021)

Bugfixes

  • Ensure no negative positions are possible when compacting
  • Fix resizing on mobile. This was caused by the ref refactor to remove ReactDOM in 1.2.3.
    • Fixes #1458
    • Note: this upgrades react-resizable to 3.0.1, which like our other deps, is only compatible with React@>=16.3.

Documentation

  • Document new arity of resizeHandle ((axis: ResizeHandleAxis, ref: ReactRef<HTMLElement>) => React$Element)
  • Remove references to the deprecated verticalCompact prop

1.2.4 (Mar 18, 2021)

This version fixes a serious render bug in <WidthProvider>. 1.2.3 should not be used.

Bugfixes

  • Fix failure to mount when layout is WidthProvider-wrapped and measureBeforeMount is true.
  • <WidthProvider> no longer updates grid with if it has been set to 0. This prevents unnecessary updates if the grid is set to display: none;. Thanks @405go #1427

1.2.3 (Mar 16, 2021)

New Features

  • React-Grid-Layout is now fully compatible with <React.StrictMode>.
    • Usage of ReactDOM has been removed by using React.createRef() inside RGL, and the new nodeRef prop in react-draggable.

1.2.2 (Mar 1, 2021)

Bugfixes

  • onResize as changed in 1.2.1 did not correctly save the layout. This is now fixed.
    • As you might guess, we need more test coverage! PRs are very welcome, I'll buy you beers on Cashapp or Patreon or whatever you like.

1.2.1 (Mar 1, 2021)

Organization Changes

We have created the React-Grid-Layout Organization! Therefore the repository has moved.

This organization will grow as time goes on, and also contains the dependencies of RGL.

Bugfixes

  • Use classList in Firefox onDragOver hack. #1310
  • Fix scale property. As scale support was added to dependencies, this caused double-compensation for scale, causing the dragged element not to follow the cursor. #1393
  • Fix horizontal compact mode issue where it inadventently would compact the bottom of the grid. This is not useful nor intended. Thanks @s4m3. #1390
  • Fix onLayoutChange sometimes not triggering on resize. We weren't cloning the layout item before modifying it. Thanks @xcqwan. #1289

Internal Refactors

  • Updated to the latest versions of all dependencies (enzyme, webpack, jest, flow).
  • Held back React@17 as enzyme is not yet ready.

1.2.0 (Nov 17, 2020)

New Features

  • You can now customize your resizable handle component as supported by react-resizable. For example:
<ReactGridLayout
  resizeHandle={<span className="custom-handle custom-handle-se" />}
  {...props}
/>

Thanks @typeetfunc #1303

Bugfixes

  • Fix onDrop handler not firing on Firefox if you drop over the placeholder.
    • Thanks @Charles-Lamoureux #1333
  • Various example style fixes #1283 #1299

1.1.1 (Sep 10, 2020)

Republish to add dist/ folder for unpkg use.

1.1.0 (Sep 3, 2020)

New Features

  • You can now place resizable handles on all corners. Use the resizeHandles prop, which is default ['se'] (for 'southeast').
    • Allowable values are:
      • '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)
    • These values may be combined, e.g. ['s', 'se', 'e'], to place three handles on the bottom side, bottom-right corner, and right side.

Bugfixes

  • Revert containerPadding change in #1138. This change was meant to be types-only, but it caused a behavioral change where the default value of containerPadding became [0, 0], not margin, which is default [10, 10].
  • Add a few more files to npmignore to improve package size.

1.0.0 (July 20, 2020)

React-Grid-Layout has been in 0.x status for far too long. With the addition of some new features in this version and a breaking change, I thought it was time to move to a stable semver.

Breaking Changes

  • onDrop callback now has a form more consistent with other callbacks.
    • Previous type: (elemParams: { x: number, y: number, w: number, h: number, e: Event }) => void
    • New type: (layout: Layout, item: ?LayoutItem, e: Event) => void
    • Thanks @ceberhar #1169
  • Dropping Node 8 compatibility and testing due to devDep incompatibilities

New Features

  • Add innerRef: React.Ref<'div'> prop to expose a ref for the grid layout's outer div. Thanks @paul-sachs #1176
  • Add isBounded property to prevent dragging items outside of the grid. Thanks @artembykov #1248

Bugfixes

  • Fix grid items stuck using percentages on first render. Thanks @rhbg #1246

0.18.3 (Mar 16, 2020)

Bugfixes

  • Fix shouldComponentUpdate interfering with droppability (#1152)

Internal Changes

  • New Enzyme test suite added to prevent regression. If you have time, we could really use more test cases that reflect your use cases!

0.18.2 (Feb 26, 2020)

Bugfixes

  • shouldComponentUpdate:
    • A too-aggressive implementation of shouldComponentUpdate was shipped in 0.18.0-0.18.1 (#1123), which did not compare the children object. While this works well in many simple implementations of RGL, it breaks in more complex applications.
    • Reference equality of props.children and nextProps.children is now added to <ReactGridLayout> and <GridItem>. If you wish to take advantage of the performance improvements from the shouldComponentUpdate work, memoize your children.
    • A section has been added to the README explaining how this works.
    • Fixed #1150, #1151.

0.18.1 (Feb 25, 2020)

This release contains typedef changes only.

Bugfixes

  • Flow types:
    • Make Props to <ReactGridLayout> and <ResponsiveReactGridLayout> exact.
    • Fix loss of props refinement when passing through WidthProvider.
    • Fix Flow errors as surfaced in #1138.
    • Modify examples to use types so that the above type error can't resurface

0.18.0 (Feb 25, 2020)

Thanks to all of our maintainers for this big release. 0.18.0 contains a large number of bugfixes that users have been asking for. Please read the full list so you know what to expect. Some of the biggest improvements include fixing changes of isResizable/isDraggable without a remount (#892), fixes to prop changes on ResponsiveReactGridLayout (#1090), shouldComponentUpdate improvements for speed (#1123), improvements to droppability (#1127), and much more.

(Potentially) Breaking Changes

  • You can now locally set isDraggable/isResizable on a static item and it will have that property. This could be useful, but be sure to check your layouts if you use static. Relates to #1060.
  • shouldComponentUpdate is now implemented on major components to improve render speed while you manipulate the layout. In our testing there are no issues. If you encounter one, please open an issue asap and we'll get it fixed. See #1123.

New Features

  • You can now manipulate isDraggable/isResizable without the child component remounting. We do this by always rendering the child <Resizable> and <Draggable> wrappers, optionally in a disabled state. This feature has been heavily requested. #892
  • The event is now passed as e on the onDrop callback. #1065
  • Pass transformScale to Resizable. #1075

Bugfixes

  • Fix handling of width changes in ResponsiveReactGridLayout. #1090
    • Fixes ignored changes of breakpoints and columns. See also issue #1083.
  • Forbid layout change on click without drag. #1044
  • Do not mutate layouts prop. #1064
  • Ensure locally set isDraggable/isResizable on a GridItem overrides the global setting on the layout. #1060
  • Avoid additional element jumping when an item is dropped. #1127
  • Don't use String#includes for Firefox test. #1096

Internal Refactors

  • Added shouldComponentUpdate to major elements for speed. Significant performance improvements while dragging. Started in #1032 and finished in #1123.
  • Internal refactor of dropping capability. It is now more predictable and uses similar unit labels (left, top) to other features. #1128
  • Upgrade devDependencies.
  • Remove ESPower from test suite (not useful with Jest).

    0.17.1 (Oct 29, 2019)


Bugfixes

  • Surround navigator check in try/catch to avoid problems with mocked navigators #1057
  • TransformScale is not applied properly while dragging an element #1046

    0.17.0 (Oct 24, 2019)


It's been 18 months since the last release, and this is a pretty large one! For references on the items below, see https://github.com/STRML/react-grid-layout/milestone/1?closed=1.

Thanks to @daynin and @n1ghtmare for taking an active role in maintaining RGL, and for giving it a much-needed shot in the arm, and thanks to the rest of our contributors.

New Features

  • Added ability to drag items into the grid from outside. #980. See the example.
    • This is especially exciting as it opens up new "widget toolbox" use cases such as Example 14 with more intuitive interaction. Thanks @daynin.
  • transformScale prop #987
  • <ResponsiveReactGridLayout> now supports margin-per-breakpoint #1016

Bugfixes

  • onWidthChange only called on breakpoint changes #770
  • Various movement bugs when compaction is off #766
  • Don't fire onDragStop if an item is only clicked, not dragged #1023
  • Fix infinite loop when dragging over a static element. #1019

Internal Refactors


  • Fixed collision issue where items below could rearrange on a move.
    • The root cause was "teleportation", or practically the same bug that leads to Pac-Man going through ghosts now and then. If a large element moves up by a few grid units, the space it vacates can suddenly become occupiable by an element below it. Rather than the collision happening properly, they exchange spaces atomically. The fix is to move items down one grid unit at a time to ensure this rearrangement does not happen.
    • Thanks @torkelo for your hard work on this for Grafana 5, which I very unfortunately managed to break when refactoring for 0.16.1.
    • Ref: #650, #739
  • Added a "Toolbox" demo (thanks @jhob)

    0.16.5 (Feb 26, 2018)


  • Minor fix to isUserAction on certain types of compaction cascades (#714, #720, #729)

    0.16.4 (Feb 15, 2018)


  • Skip null items in processGridItem (#578)
  • Resize is broken for grids with preventCollision: true, fixes #655 (#656)
  • Minor refactoring

    0.16.3 (Jan 31, 2018)


  • Fix overriding of onStart behaviour (#707, thanks @ersel)
  • Fixed Flow type of WidthProvider
  • Devdep updates

    0.16.2 (Dec 17, 2017)


  • Fix onLayoutChange not firing properly due to regression introduced in 0.16.1
  • Simpler resize corner CSS (thanks @TrySound)
  • Reformat code with Prettier & simplify lint configs (thanks @TrySound)

    0.16.1 (Dec 10, 2017)


  • Flow def upgrades (thanks @TrySound)
  • DevDep upgrades
  • Fixed WebpackBin demo
  • Addl test cases (thanks @torkelo)

    0.16.0 (Oct 6, 2017)


  • Added horizontal compaction option, compactType (thanks @Rhjulskov)
  • Added preventCollision option for static grids (thanks @EmrysMyrddin)

    0.15.2 (Sep 5, 2017)


  • Fix missed import *
  • Dependency updates

    0.15.1 (Sep 5, 2017)



  • Package upgrades, including Webpack 3
  • Flow typedef upgrades for the 0.53 rework
  • Add faulty key value in duplicate key error message (#602)

    0.14.7 (Jul 14, 2017)



  • Fixed a bad publish (connectivity issue).

    0.14.5 (Apr 19, 2017)


  • Moved to prop-types package to avoid React.PropTypes deprecation in 15.5. Thanks @inverts!

    0.14.4 (Mar 9, 2017)


Fixes:

  • Typecheck in WidthProvider to satisfy Flow (and technically, this could be a Text node)
Dev:
  • Update Flow

    0.14.3 (Feb 22, 2017)


Fixes:

  • Reverted #499; msTransform is indeed correct. See discussion.

    0.14.2 (Feb 22, 2017)


Fixes:

  • Fixed use of MSTranform for IE. Thanks @dvoaviarison (#499)
  • Fix generation of source maps, which was temporarily broken by the webpack 2 upgrade.

Internal:

  • Update development dependencies and babel version.

    0.14.1 (Feb 20, 2017)


Fixes:

  • Fixed a minor Flow type issue when a classnames typedef is present.
  • Fixed a scoping issue when running make build-example.

    0.14.0 (Feb 13, 2017)


Features:

  • New test suite - thanks @nikolas
  • Dev Dependency updates
  • Committed yarn.lock
  • Added react-draggable classname to draggable grid items.

    0.13.9 (Oct 13, 2016)


Fixes:

  • Fixed sorting of layout items, which could be different in IE if two items have the same x & y coordinate.

    • See #369.

      0.13.8 (Oct 13, 2016)


Fixes:

  • Fixed breakage introduced in 0.13.7 when items are added without a layout or data-grid property.

    • See #368.

      0.13.7 (Oct 3, 2016)


Fixes:

  • Fixed an error during layout sync if children was a keyed fragment or had nested arrays.
  • Fixed onLayoutChange being called when layout didn't change.
  • Fixed some issues with input layout items being modified in-place rather than cloned.
  • Minor typos.

    0.13.6 (Sep 26, 2016)


Fixes:

  • Fixed missing HTMLElement in onResize* callbacks.

    0.13.5 (Sep 9, 2016)


Fixes:

  • Fixed a few Flow typing errors in WidthProvider.

    0.13.4 (Sep 9, 2016)


Fixes:

  • Fixed potential call to ReactDOM.findDOMNode(this) after unmount of WidthProvider.
  • Fixed an issue where layout items using data-grid could rearrange on mount depending on how they were ordered.

    • See #342 for reference.

      0.13.3 (Aug 31, 2016)


Fixes:

  • Fixed lodash.isequal import, which was ruined by case-insensitive HFS+ shakes fist

    0.13.2 (Aug 31, 2016)


Fixes:

  • Diffing children in order to regenerate the layout now diffs the key props and their order.
    • This will catch more changes, such as sorting, addition, and removal.
  • Only pass className and style to WidthProvider. Other props were not intended to be supported.
    • I'm aware this could be a breaking change if you were relying on this bad behavior. If so, please use your own WidthProvider-style HOC.
  • babel-plugin-transform-flow-comments had limited support for defining types like transpiled classes.

    • This has been updated to instead copy source to .js.flow files, which preserves all type information.

      0.13.1 (Aug 16, 2016)


Fixes:

  • Fix remaining propTypes warnings.

    0.13.0 (Aug 3, 2016)


Changed:

  • Due to a change in React 15.2, passing the _grid property on DOM children generates an error. To compensate, we now error on the same and suggest using data-grid instead. Simply change any use of _grid to data-grid, or add your properties to the layout.

Fixes:

  • Fix React 15.3 warning re: propTypes.

    0.12.7 (Jun 29, 2016)


  • Prevent extraenous rerenders in <ResponsiveReactGridLayout> by using deep equality on layouts.

    0.12.6 (Jun 5, 2016)


  • Fix blindingly obvious bug where mounted isn't set to true. Smack forehead.

    0.12.5 (Jun 3, 2016)


  • Fixes for server rendering checksum failures.

    0.12.4 (May 22, 2016)


  • Update to React-Draggable v2. Fixes: #241, #239, #24

    • v2 contains a number of bugfixes & enhancements for touchscreens, multitouch, and scrolling containers.

      0.12.3 (May 3, 2016)


  • Bugfix: Rendering with new breakpoints/cols does not refresh the layout. Fixes #208 - thanks @damienleroux

    0.12.2 (May 1, 2016)


  • Bugfix: Fix warning about undefined useCSSTransforms when server-rendering.

    0.12.1 (Apr 19, 2016)


  • Bugfix: Don't set layout twice on width change. See #217 - thanks @damienleroux
  • Enhancement: Add Flow type comments

    0.12.0 (Apr 14, 2016)


  • <ReactGridLayout> will no longer animate so severely on mount. See #212.
    • If you are using <WidthProvider>, you may notice that the container's width still shunts on mount. If you like, you may delay mounting by setting measureBeforeMount={true} on the wrapped element. This will eliminate the mounting animation completely.
    • If you enjoyed the old animation, set useCSSTransforms={this.state.mounted} and toggle the mounting flag. See 0-showcase.jsx for an example.
  • Set more permissive version ranges for <Draggable> and <Resizable> dependencies, as they are now stable and will only introduce breaking changes on major version ticks.

    0.11.3 (Apr 8, 2016)


  • Officially support React v15.

    0.11.2 (Apr 6, 2016)


  • Bugfix: Draggable cancel selectors, see #203 - thanks @RiiD
  • README fixes, thanks @bravo-kernel & @ro-savage

    0.11.1


  • Bugfix: <ResponsiveReactGridLayout> was using stale data when synchronizing children with the layout on a breakpoint change.

    0.11.0


This release contains potentially breaking changes so I have updated the minor version (as per semver).

Breaking Changes:

  • Layout items now have a fixed set of properties. Other properties will not be merged into the <GridItem>, such as className. To set a className on a child, set it on the child directly and it will be merged. This allows us to make better assumptions about the layout and use a faster cloning mechanism.
  • Setting individual handle and cancel selectors per item is no longer supported. If you need this, please open a ticket and let me know your use case.

Other changes:

  • Bugfix: <ResponsiveReactGridLayout> onLayoutChange callback data could still be stale.
  • Bugfix: Range error when building layout solely from _grid properties.
    • This broke a lot of usage and thus 0.10.11 and 0.10.10 have been unpublished.
  • Removed redundant isPlaceholder property from <GridItem>.
  • README updates to clarify layout/_grid usage.

    0.10.11


  • Bugfix: layouts param on <ResponsiveReactGridLayout>'s onLayoutChange could have stale data for the current breakpoint.

    0.10.10


  • Performance: Prevent V8 deopt in a few methods and add fast layout item cloning.

    0.10.9


  • Bugfix: Typo in children comparison in CWRP. See #169.
  • Bugfix: Missing babel-preset-es2015 in dev.

    0.10.8



  • Bugfix: className and style props on grid children were being incorrectly dropped, a holdover from when cloneWithProps() used to do this merging for us. They are now merged.

    0.10.6


  • Bugfix: If both props.layout and props.children.length change in the same tick, props.layout would be clobbered. See #162

    0.10.5


  • Bugfix/Enhancement: Margins were causing subtle error in some of the positioning calculations. This has been fixed.

    0.10.4


  • Bugfix: Container height was calculated as less than expected due to improper addition of margin.

    0.10.3


  • Bugfix: Round item positions even if they're currently resizing or dragging (#158, regression of #141)
  • Bugfix: Fix a positioning bug when margins are 0 (#160)

    0.10.2


  • Bugfix: <RGL> would synchronize children with layout if the layout in props didn't match the state; this was meant to be a hook for the developer to supply a new layout. The incorrect check could cause the layout to reset if the parent rerendered. The check is now between the layout in nextProps and props.
  • Bugfix: Fixed a lot of resizing layout bugs; most of the fixes are in react-resizable.
  • Bugfix: Fixed incorrect typecheck on LayoutItem.i.
  • Bugfix: Make onLayoutChange fire appropriately (#155).
  • Bugfix: Fix <ResponsiveGridLayout> not properly reverting when sizing the page up (#154).
  • Remove unused offsetX and offsetY from layouts.
  • Dependency updates.

    0.10.1


  • Hotfix for default export incompatibility caused by Babel 6.

    0.10.0


This long-awaited release provides React 0.14 compatibility and a rewrite of the underlying <Draggable> functionality.

Breaking changes:

  • ListensToWidth replaced with WidthProvider which must wrap <ResponsiveReactGridLayout> and <ReactGridLayout> to provide width data. See doc for example.
  • Prop initialWidth renamed to width.
  • Grid Layout keys must be type of string now.

Other changes:

  • Finally compatible with React 0.14! Big thanks to @menelike for his help.
  • Upgraded to Babel 6.
  • Full typechecking via Flow.
  • Lots of misc bugfixes.

    • See beta releases below for more details.

      0.10.0-beta1


  • Fixed a React import bug on ListensToWidth.jsx (#130; thanks @mrblueblue)

    0.10.0-beta0


This release is unstable!

  • React 0.14 compatibility.
  • This release includes a rewrite of much of the project in ES6/7 style with Flow typing.
  • This release brings us onto mainline (1.x) react-draggable and react-resizable, eliminating the previous github dependency.
  • 0.10.0 is not yet complete. Use this release at your own risk.

Known bugs:

  • The placeholder box does not properly follow the mouse and stays pinned to the active drag.

0.9.2

  • Update react-draggable to v0.8.0 to fix IE11 issues (#29).

    0.9.1


  • Update react-draggable to v0.7.3 to fix a bounds bug (#56).

    0.9.0


  • Move off react-draggable fork to mainline v0.7.2. Incremented minor (major in the case of npm's ^, since we are pre-v1) version in case of unforeseen conflicts.

    0.8.3


  • Add verticalCompact toggle.

    0.8.2


  • Fix a crash when initializing with no children.

    0.8.1


  • Fixed React 0.13 warning about isMounted().
  • Update to babel 5.
  • Added browser build for use with a <script> tag or in RequireJS builds.
  • Pinned react-draggable version in anticipation of React 0.13 update.

    0.8.0


  • Changed signature on resize/drag callbacks to allow dynamic max/min W/H per item.
  • Fixed bug in useCSSTransforms.
  • Documentation and example fixes.

    0.7.1


  • Added callbacks for resize and drag start/active/stop.

    0.7.0


Breaking changes:

  • ReactGridLayout.props.handle renamed to ReactGridLayout.props.draggableHandle.

This version contains a CSS update. This fixes a visual bug where you may see items quickly reset position and animate back to their original position on load, when you are using CSS transforms. To fix this bug, copy the rules from css/styles.css into your stylesheet.

Other changes:

  • Fixed #19 (bad new item placement with css transforms).
  • Fixed some placement inconsistencies while RGL is mounting, with css transforms and percentages.
  • Fixed a duplicate className bug.

    0.6.2


  • Fix #21 (error when passing only a single child).
  • Add GridItem.props.cancel.
  • Use React addons directly to save file size.
  • Allow setting draggable/resizable per grid item, as well as existing static property.
  • Use object.assign to set _grid properties so we can more easily merge PRs in the future.

    0.6.1


  • Fixed #8 (current layout was not properly being stored when provided via _grid props).

    0.6.0


  • Optionally use CSS transforms for placement, fallback on position top/left.
  • Allow parent to set responsive breakpoint directly.

    0.5.2


  • Fix Responsive import for node users

    0.5.1


  • Add support for min/max dimension attributes.
  • Example tweak

    0.5.0


  • Refactoring and demo tweaks. Update README with new params.
  • Add showcase example, tweak template
  • Refactor: Responsive Grid Layout is a separate element
  • Auto-generate examples from template rather than edit them individually.

    0.4.0


  • Force lodash into commons chunk
  • More tweaks to grid collisions. This should fix bad swaps once and for all.
  • Set unused:"vars" in lint.
  • Add responsive localstorage example and initialLayouts support.
  • Fix localstorage example comment.
  • Rework responsive layouts, identify child elements by key rather than index. Added 2 new examples.
  • Fixup GridItem resizing feel a bit.

< 0.4.0

  • Early development versions, too many changes to list.