Gridstack.js: Responsive Drag-and-Drop Grid Layout

File Size: 456 KB
Views Total: 135701
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   
Gridstack.js: Responsive Drag-and-Drop Grid Layout

Gridstack.js is a vanilla JavaScript and TypeScript grid layout library that creates draggable, resizable, and responsive dashboard widgets. Inspired by the legacy jQuery Gridster plugin.

You can use it to create customizable admin panels, analytics dashboards, portal-style layouts, and widget-based interfaces where users can rearrange content.

Note that current Gridstack.js releases do not require jQuery, while legacy jQuery projects should use the older jQuery-compatible build.

More features:

  • Also supports touch events.
  • Resizable grid items.
  • Supports nested grid items.
  • Compatible with Bootstrap framework.
  • No jQuery required (v5.1.1+)

Alternatives:

Table Of Contents:

Basic Usage (Vanilla JS Version):

1. Install & Download the package.

# Yarn
$ yarn add gridstack

# NPM
$ npm install gridstack --save

2. Include the necessary JavaScript and CSS files on the page.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gridstack@latest/dist/gridstack.min.css" />
<script src="https://cdn.jsdelivr.net/npm/gridstack@latest/dist/gridstack.all.js"></script>

3. Insert optional grid items to the Grid Stack container and pass the options via data-option attributes as follows:

<div class="grid-stack">
  <div class="grid-stack-item">
    <div class="grid-stack-item-content">Item 1</div>
  </div>
  <div class="grid-stack-item" data-gs-width="2">
    <div class="grid-stack-item-content">Item 2 wider</div>
  </div>
</div>

4. Initialize the plugin and done.

var grid = GridStack.init();

5. All default grid options.

var grid = GridStack.init({

    // accept widgets dragged from other grids or from outside
    // true (uses '.grid-stack-item' class filter) or false
    // string for explicit class name
    // function (i: number, element: Element): boolean
    acceptWidgets: false,

    // false: the resizing handles are only shown while hovering over a widget
    // true: the resizing handles are always shown
    // 'mobile': if running on a mobile device, default to true, else false
    alwaysShowResizeHandle: 'mobile',

    // turns animation on
    animate: false,

    // amount of columns and rows
    column: 12,

    // column options
    // see below
    columnOpts: {
      // wanted width to maintain (+-50%) to dynamically pick a column count
      columnWidth?: number;
      // maximum number of columns allowed (default: 12). Note: make sure to have correct CSS to support this.
      columnMax?: number ;
      // global re-layout mode when changing columns
      layout?: ColumnOptions ;
      // specify if breakpoints are for window size or grid size (default:false = grid)
      breakpointForWindow?: boolean;
      // explicit width:column breakpoints instead of automatic 'columnWidth'. 
      // Note: make sure to have correct CSS to support this.
      breakpoints?: Breakpoint[]; 
    },
    row: 0,

    // max/min number of rows
    maxRow: 0,
    minRow: 0,

    // if you are using a nonce-based Content Security Policy, pass your nonce here and GridStack will add it to the <style> elements it creates
    nonce: '',

    // minimal width before grid will be shown in one column mode (default?: 768) */
    oneColumnSize: 768,

    // set to true if you want oneColumnMode to use the DOM order and ignore x,y from normal multi column layouts during sorting. 
    // This enables you to have custom 1 column layout that differ from the rest. (default?: false)
    oneColumnModeDomSort: false,

    // widget class
    itemClass: 'grid-stack-item',

    // class for placeholder
    placeholderClass: 'grid-stack-placeholder',

    // text for placeholder
    placeholderText: '',

    // draggable handle selector
    handle: '.grid-stack-item-content',

    // class for handle
    handleClass: null,

    // allow for selecting older behavior (adding STYLE element to HEAD element instead of parentNode)
    styleInHead: false,

    // an integer (px)
    // a string (ex: '100px', '10em', '10rem'). Note: % doesn't right - see CellHeight
    // 0, in which case the library will not generate styles for rows. Everything must be defined in your own CSS files.
    // auto - height will be calculated for square cells (width / column) and updated live as you resize the window
    // initial - similar to 'auto' (start at square cells) but stay that size during window resizing.
    cellHeight: 'auto',

    // throttle time delay (in ms) used when cellHeight='auto' to improve performance vs usability
    cellHeightThrottle: 100,

    // list of children items to create when calling load() or addGrid()
    // see item options below
    children: [],

    // additional class on top of '.grid-stack' (which is required for our CSS) to differentiate this instance.
    class: '',

    // Can be:
    // an integer (px)
    // a string (ex: '2em', '20px', '2rem')
    margin: 10,

    // or
    marginTop: 10,
    marginBottom: 10,
    marginLeft: 10,
    marginRight: 10

    // if false it tells to do not initialize existing items
    auto: true,

    // enable floating widgets
    float: false,

    // makes grid static
    staticGrid: false,

    // false the resizing handles are only shown while hovering over a widget
    // true the resizing handles are always shown
    // 'mobile' if running on a mobile device, default to true (since there is no hovering per say), else false. this uses this condition on browser agent check: alwaysShowResizeHandle: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( navigator.userAgent )
    alwaysShowResizeHandle: 'mobile',

    // allows to owerride jQuery UI draggable options
    draggable: {
      handle: '.grid-stack-item-content', 
      scroll: true, 
      appendTo: 'body'
    },

    // lets user drag nested grid items out of a parent or not
    dragOut: false,

    // make gridItems size themselves to their content, calling resizeToContent(el) whenever the grid or item is resized
    sizeToContent: true,

    // allows to owerride jQuery UI resizable options
    // handles can be any combo of n,ne,e,se,s,sw,w,nw or all
    resizable: {handles: 'se'},

    // disallows dragging of widgets
    disableDrag: false

    // disallows resizing of widgets
    disableResize: false,

    // if `true` turns grid to RTL. 
    // Possible values are `true`, `false`, `'auto'`
    rtl: 'auto',

    // if `true` widgets could be removed by dragging outside of the grid
    removable: false,

    // time in milliseconds before widget is being removed while dragging outside of the grid
    removeTimeout: 2000,
    
});

6. All default item options.

var grid = GridStack.init({

    children: [
      {
        // element position
        x:1,
        y:0, 

        // element size
        w: 2,
        h: 4,

        // min/max width and height
        maxW: 'none',
        minW: 'none',
        maxH: 'none',
        minH: 'none',

        // unique ID (number of string)
        id: 1,

        // html content
        content: 'regular item',

        // enables auto position
        autoPosition: true,

        // locks the item
        locked: false,

        // enables/disables resizable
        noResize: false,

        // enables/disables draggable
        noMove: false,

        // items can can have their own custom resize handle
        resizable: {handles: string},

        // boolean | number - make gridItem size itself to the content
        // calling GridStack.resizeToContent(el) whenever the grid or item is resized.
        sizeToContent: true,

        // sub grid
        subGrid: {children: sub1, class: 'sub1', ...subOptions},

        // enables/disables the creation of sub-grids on the fly by dragging items completely over others (nest) vs partially (push)
        subGridDynamic: true,
        
      },
      // more items here
    ]
    
});

7. API methods.

// Initialize
let grid = GridStack.init(options, GridStackElement);

// Initialize a list of elements (given a selector) and return an array of grids.
let grids = GridStack.initAll(options, selector);

// Create a grid with the given options
let grids = GridStack.addGrid(parent, options);

// Setup dragging in from the outside (say toolbar), by specifying the class selection and options
let grids = GridStack.setupDragIn(dragIn, dragInOptions);

// Specify global custom engine subclass
let grids = GridStack..registerEngine(engineClass: typeof GridStackEngine);

// Creates a new widget.
grid.addWidget(el, {
  // options
  x, y, width, height, autoPosition, minWidth, maxWidth, minHeight, maxHeight, id, locked, noResize, noMove, resizeHandles
});

// Initailizes batch updates. 
// You will see no changes until commit method is called.
grid.batchUpdate();

// Relayout grid items to reclaim any empty space.
grid.compact();

// Gets current cell height.
grid.cellHeight(val: number, update = true);

// Update current cell height.
// grid.cell_height(grid.cell_width() * 1.2);
grid.cellHeight(val, noUpdate);

// Gets current cell width.
grid.cellWidth();

// Set/get the number of columns in the grid
// Require gridstack-extra.min.css
grid.column(column: number, layout: ColumnOptions = 'moveScale');

// Destroy the instance
// removeDOM - if false nodes and grid will not be removed from the DOM
grid.destroy([removeDOM]);

// Enables/disables the plugin
grid.enable();
grid.disable();

// Enables/disables widget moving. 
grid.enableMove(doEnable);

// Enables/disables widget resizing
grid.enableResize(doEnable);

// Set/get floating widgets
// val - boolean to set true/false, else get the current value
grid.float(val);

// Get current cell height
grid.getCellHeight();

// Get the position of the cell under a pixel on screen.
// position - the position of the pixel to resolve in absolute coordinates, as an object with top and leftproperties
// useOffset - if true, value will be based on offset vs position (Optional. Default false). Useful when grid is within position: relative element
// Returns an object with properties x and y i.e. the column and row in the grid.
grid.getCellFromPixel(position, useOffset);

// Returns the number of columns in the grid.
grid.getColumn();

// Returns list of GridItem HTML dom elements (excluding temporary placeholder)
grid.getGridItems();

// Returns current margin value.
grid.getMargin();

// Checks if specified area is empty.
grid.isAreaEmpty(x, y, width, height);

// Load the widgets from a list
grid.load(layout: GridStackWidget[], boolean | ((w: GridStackWidget, add: boolean) => void) = true);

// Make new widgets after new items are appended to the grid.
grid.makeWidget(el);

// Set the top/right/bottom/left margin between grid item and conten
grid.margin(value: numberOrString);

// Disables / enables widgets moving/resizing.
// el - widget to modify
// val - if true widget will be draggable.
grid.movable(el, val);


// Removes widget from the grid.
// el - widget to remove.
// removeDOM - if false node won't be removed from the DOM (Optional. Default true).
// triggerEvent if false (quiet mode) element will not be added to removed list and no 'removed' callbacks will be called (Default true).
grid.removeWidget(el, removeDOM = true, triggerEvent = true);

// Removes all widgets from the grid.
// removeDOM - if false nodes won't be removed from the DOM (Optional. Default true).
grid.removeAll(removeDOM = true);

// Enables/Disables user resizing of specific grid element.
// el - widget to modify
// val - if true widget will be resizable.
grid.resizable(el, val); 

// Returns the layout of the grid that can be serialized (list of item non default attributes, not just w,y,x,y but also min/max and id). 
// saveContent if true (default) the latest html inside .grid-stack-content will be saved to GridStackWidget.content field, else it will be removed.
// saveGridOpt if true (default false), save the grid options itself, so you can call the new GridStack.addGrid() to recreate everything from scratch. GridStackOptions.children would then contain the widget list instead.
// returns list of widgets or full grid option, including .children list of widgets
grid.save(saveContent = true, saveGridOpt = false);

// Toggle the grid animation state.
// doAnimate - if true the grid will animate.
grid.setAnimation(doAnimate);

// Update widget position/size.
grid.setStatic(staticValue);

// Toggle the grid static state
// staticValue - if true the grid becomes static.
grid.update(el, x, y, width, height));

// Returns true if the height of the grid will be less the vertical constraint. Always returns true if grid doesn't have height constraint.
grid.willItFit(x, y, width, height, autoPosition);

8. Event handlers.

grid.on('added', function(event, items) {
  // after new items are added
});

grid.on('change', function(event, items) {
  // fired on change
});

grid.on('disable', function(event) {
  // var grid = event.target;
});

grid.on('dragstart', function(event, ui) {
  // var grid = this;
  // var element = event.target;
});

grid.on('drag', function(event, el) {
  // fired on resize
});

grid.on('dragstop',  function(event, ui) {
  // var grid = this;
  // var element = event.target;
});

grid.on('dropped',  function(event, previousWidget, newWidget) {
  // after dropped
});

grid.on('enable',  function(event) {
  // var grid = event.target;
});

grid.on('removed',  function(event, items) {
  // after removed
});

grid.on('resizestart',  function(event, el) {
  // var grid = this;
  // var element = event.target;
});

grid.on('resize', function(event, el) {
  // fired on resize
});

grid.on('resizestop',  function(event, items) {
  // on stop resizing
});

Basic Usage (jQuery Version):

1. Include jQuery library and other required resources in the the document.

  • jQuery
  • jQuery UI
  • jQuery UI Touch Punch: for touch support (OPTIONAL)
  • gridstack.poly.js: for IE and older browsers (OPTIONAL)
<!-- Local -->
<link href="/path/to/gridstack.css" rel="stylesheet" />
<!-- Or From A CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gridstack@latest/dist/gridstack.min.css" />

2. Include the jQuery Gridstack.js plugin and other required resources at the end of the document.

<!-- Dependencies -->
<script src="/path/to/cdn/jquery.min.js"></script>
<script src="/path/to/cdn/jquery-ui.min.js"></script>
<script src="/path/to/cdn/jquery.ui.touch-punch.min.js"></script>

<!-- jQuery Gridstack.js -->
<script src="gridstack.all.js"></script>
<!-- Or from a CDN -->
<script src="https://cdn.jsdelivr.net/npm/gridstack@latest/dist/gridstack.all.js"></script>
<!-- Polyfill for old IE -->
<script src="gridstack.poly.js"></script>

3. Create a sample draggable grid layout as follows.

  • gs-animate: turns animation on (for grid)
  • gs-column: amount of columns (for grid)
  • gs-max-row: maximum rows amount, defaults to 0 (for grid)
  • gs-current-height: current rows amount (for grid)
  • gs-id: unique ID (for item)
  • gs-x, data-gs-y: element position (for item)
  • gs-width, data-gs-height: element size (for item)
  • gs-max-widthgs-min-width, gs-max-height, gs-min-height: element constraints (for item)
  • gs-no-resize: disable element resizing (for item)
  • gs-no-move: disable element moving (for item)
  • gs-auto-position: tells to ignore data-gs-x and data-gs-y attributes and to place element to the first available position (for item)
  • gs-locked: the widget will be locked. It means another widgets couldn't move it during dragging or resizing. The widget is still can be dragged or resized. You need to add data-gs-no-resize and data-gs-no-move attributes to completely lock the widget (for item)
  • gs-resize-handles: resize handles (for item)
  • gs-static-grid: whether to make grid static
<div class="grid-stack" data-gs-width="12">
  <div class="grid-stack-item" gs-x="0" data-gs-y="0" gs-width="4" gs-height="2">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="4" data-gs-y="0" gs-width="4" gs-height="4">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="8" gs-y="0" gs-width="2" gs-height="2" gs-min-width="2" gs-no-resize="yes">
    <div class="grid-stack-item-content"> <span class="fa fa-hand-o-up"></span> Drag me! </div>
  </div>
  <div class="grid-stack-item" gs-x="10" gs-y="0" gs-width="2" gs-height="2">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="0" gs-y="4" gs-width="2" gs-height="2">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="2" gs-y="4" gs-width="2" gs-height="4">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="8" gs-y="4" gs-width="4" gs-height="2">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="0" gs-y="6" gs-width="2" gs-height="2">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="4" gs-y="6" gs-width="4" gs-height="2">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="8" gs-y="6" gs-width="2" gs-height="2">
    <div class="grid-stack-item-content"></div>
  </div>
  <div class="grid-stack-item" gs-x="10" gs-y="6" gs-width="2" gs-height="2">
    <div class="grid-stack-item-content"></div>
  </div>
</div>

4. Call the plugin and create a responsive & fluid 12 columns grid layout.

$(function () {
  $('.grid-stack').gridstack({
    column: 12
  });
});

5. All possible options and defaults available.

$('.grid-stack').gridstack({

  // accept widgets dragged from other grids or from outside
  // true (uses '.grid-stack-item' class filter) or false
  // string for explicit class name
  // function (i: number, element: Element): boolean
  acceptWidgets: false,

  // turns animation on
  animate: false,

  // amount of columns
  column: 12,

  // max/min number of rows
  maxRow: 0,
  minRow: 0

  // maximum rows amount
  height: 0, 

  // widget class
  itemClass: 'grid-stack-item',

  // class for placeholder
  placeholderClass: 'grid-stack-placeholder',

  // text for placeholder
  placeholderText: '',

  // draggable handle selector
  handle: '.grid-stack-item-content',

  // class for handle
  handleClass: null,

  // allow for selecting older behavior (adding STYLE element to HEAD element instead of parentNode)
  styleInHead: false,

  // one cell height
  cellHeight: 60,

  // gap size
  // e.g. '5px 10px 0 20px' or '5em 10em'
  margin: 10,

  // unit
  verticalMarginUnit: 'px',
  cellHeightUnit: 'px',

  // if false it tells to do not initialize existing items
  auto: true,
  
  // minimal width.
  minWidth: 768,

  // class set on grid when in one column mode
  oneColumnModeClass: 'grid-stack-one-column-mode',

  // set to true if you want oneColumnMode to use the DOM order and ignore x,y from normal multi column layouts during sorting. This enables you to have custom 1 column layout that differ from the rest.
  oneColumnModeDomSort: false,

  // enable floating widgets
  float: false,

  // makes grid static
  staticGrid: false,

  // if true the resizing handles are shown even the user is not hovering over the widget
  alwaysShowResizeHandle: false,

  // allows to owerride jQuery UI draggable options
  draggable: {handle: '.grid-stack-item-content', scroll: true, appendTo: 'body', containment: null},

  // let user drag nested grid items out of a parent or not
  dragOut: false,

  // allows to owerride jQuery UI resizable options
  resizable: {autoHide: true, handles: 'se'},

  // disallows dragging of widgets
  disableDrag: false

  // disallows resizing of widgets
  disableResize: false,

  // if `true` turns grid to RTL. 
  // Possible values are `true`, `false`, `'auto'`
  rtl: 'auto',

  // if `true` widgets could be removed by dragging outside of the grid
  removable: false,

  // time in milliseconds before widget is being removed while dragging outside of the grid
  removeTimeout: 2000,

  // CSS class when in one column mode
  disableOneColumnMode: 'grid-stack-one-column-mode',

  // class that implement drag'n'drop functionallity for gridstack
  ddPlugin: null

});

6. API methods methods.

// Creates a new widget.
grid.addWidget(el, x, y, width, height, autoPosition, minWidth, maxWidth, minHeight, maxHeight, id);

// Initailizes batch updates. 
// You will see no changes until commit method is called.
grid.batchUpdate();

// Relayout grid items to reclaim any empty space.
grid.compact();

// Gets current cell height.
grid.cellHeight();

// Update current cell height.
// grid.cell_height(grid.cell_width() * 1.2);
grid.cellHeight(val, noUpdate);

// Gets current cell width.
grid.cellWidth();

// Returns current vertical margin value.
grid.verticalMargin();

// value - new vertical margin value.
// noUpdate - if true, styles will not be updated.
grid.verticalMargin(value, noUpdate)

// Finishes batch updates. Updates DOM nodes. You must call it after batch_update.
grid.Commit();

// set/get floating widgets
grid.float(val);

// Disables / enables widgets moving/resizing.
grid.movable('.grid-stack-item', false);
grid.resizable('.grid-stack-item', true); 

// Get the position of the cell under a pixel on screen.
// position - the position of the pixel to resolve in absolute coordinates, as an object with top and leftproperties
// useOffset - if true, value will be based on offset vs position (Optional. Default false). Useful when grid is within position: relative element
// Returns an object with properties x and y i.e. the column and row in the grid.
grid.getCellFromPixel(position, useOffset);

// Checks if specified area is empty.
grid.isAreaEmpty(x, y, width, height);

// Locks/unlocks widget.
// el - widget to modify.
// val - if true widget will be locked.
grid.locked(el, val);

// Make new widgets after new items are appended to the grid.
grid.makeWidget(el);

// Set the minWidth/maxWidth for a widget.
grid.minWidth(el, val);
grid.maxWidth(el, val);

// Set the minHeight/maxWidth for a widget.
grid.minHeight(el, val);
grid.maxHeight(el, val);

// Removes widget from the grid.
// detachNode - if false node won't be removed from the DOM
grid.removeWidget(el, detachNode);

// Removes all widgets from the grid.
// detachNode - if false node won't be removed from the DOM
grid.removeAll(detachNode);

// Changes widget size
grid.resize(el, width, height);

// Changes widget position
grid.move(el, x, y);

// Enables/Disables resizing.
grid.resizable(el, val);

// Enables/Disables moving.
grid.movable(el, val);

// Updates widget position/size.
grid.update(el, x, y, width, height);

// Returns true if the height of the grid will be less the vertical constraint. Always returns true if grid doesn't have height constraint.
grid.willItFit(x, y, width, height, autoPosition);

// Toggle the grid animation state.
// doAnimate - if true the grid will animate.
grid.setAnimation(doAnimate);

// Modify number of columns in the grid
// doNotPropagate - if true existing widgets will not be updated.
// NOTE: Use column() instead in v1.0+
grid.setColumn(column, doNotPropagate);

// Update widget position/size.
grid.setStatic(staticValue);

// Toggle the grid static state
// staticValue - if true the grid becomes static.
grid.update(el, x, y, width, height));

// Gets called after a widget has been updated (eg: load() after initial layout) instead of created
grid.updateCB(w);

// Destroy the instance
// detachGrid - if false nodes and grid will not be removed from the DOM
grid.destroy([detachGrid]);

// Enables/disables the plugin
grid.enable();
grid.disable();

// Enables/disables widget moving. includeNewWidgets will force new widgets to be draggable as per doEnable's value by changing the disableDrag grid option.
grid.enableMove(doEnable, includeNewWidgets);

// Enables/disables widget resizing. includeNewWidgets will force new widgets to be resizable as per doEnable's value by changing the disableResize grid option. 
grid.enableResize(doEnable, includeNewWidgets);

7. Event listeners available.

$('.grid-stack').on('added', function(event, items) {
  // after new items are added
});

$('.grid-stack').on('change', function(event, items) {
  // fired on change
});

$('.grid-stack').on('disable', function(event) {
  // var grid = event.target;
});

$('.grid-stack').on('dragstart', function(event, ui) {
  // var grid = this;
  // var element = event.target;
});

$('.grid-stack').on('dragstop',  function(event, ui) {
  // var grid = this;
  // var element = event.target;
});

$('.grid-stack').on('dropped',  function(event, previousWidget, newWidget) {
  // after dropped
});

$('.grid-stack').on('enable',  function(event) {
  // var grid = event.target;
});

$('.grid-stack').on('removed',  function(event, items) {
  // after removed
});

$('.grid-stack').on('resizestart',  function(event, ui) {
  // var grid = this;
  // var element = event.target;
});

$('.grid-stack').on('gsresizestop',  function(event, items) {
  // on stop resizing
});

Changelog:

v12.6.0 (2026-04-09)

  • Full RTL support
  • Bugfixes

v12.5.0 (2025-04-06)

  • touch device with real mouse event fix

v12.4.2 (2025-12-27)

  • touch device with real mouse event fix

v12.4.1 (2025-12-15)

  • Custom resize div element target
  • Bugfixes

v12.3.3 (2025-08-14)

  • bugfix

v12.3.2 (2025-08-13)

  • more tweaks to save(columnCount) option.

v12.3.1 (2025-08-12)

  • added save(columnCount) option. Nested grid now use container saved column count.

v12.3.0 (2025-08-11)

  • added .grid-stack-dragging to grid when child is being dragged so we can set cursor:grabbing.
  • fixed bugs.

v12.2.2 (2025-07-07)

  • bugfixes

v12.2.1 (2025-05-28)

  • added GridStack.updateCB(w) that gets called after a widget has been updated (eg: load() after initial layout) instead of created

v12.1.2 (2025-05-08)

  • bugfixes

v12.1.1 (2025-04-29)

  • bugfixes

v12.1.0 (2025-04-24)

  • bugfixes
  • removed ES5 support
  • remove legacy code support for disableOneColumnMode, oneColumnSize, oneColumnModeDomSort

v12.0.0 (2025-03-17)

  • feat: Removed dynamic stylesheet and migrated to CSS vars. Thank you lmartorella
  • feat: columns no longer require custom classes nor gridstack-extra.css as we now use CSS vars.
  • fix: Very slow operation in 11.2.0 and higher with large blocks
  • fix: loading responsive layout:'list' into smaller screen doesn't layout correctly.

v11.5.0 (2025-03-17)

  • prepareDragDrop(el, force) option to force re-creation of the drag&drop event binding
  • new updateOptions(o: GridStackOptions) to update PARTIAL list of options after grid as been created
  • bugfixes

v11.4.0 (2025-02-28)

  • internal _prepareDragDropByNode(n) is now public as prepareDragDrop(el) so Angular, React, and others can call once the DOM content elements have been added (the outside grid item divs are always created before content)
  • bugfixes

v11.3.0 (2025-01-17)

  • feat: added isIgnoreChangeCB() if changeCB should be ignored due to column change, sizeToContent, loading, etc...
  • feat: added responsive_none.html demo and fixed layout:'none' to bound check the layout (no-op unless it must change)

v11.2.0 (2024-12-30)

  • 'Esc' to cancel now works on sidebar external items, also works dragging over trash.
  • Bugfixes

v11.1.2 (2024-12-10)

  • Bugfixes

v11.1.1 (2024-11-27)

  • Bugfixes

v11.1.0 (2024-11-18)

  • Bugfixes
  • added GridStackOptions.layout for nested grid reflow during resize. default to 'list'.

v11.0.1 (2024-10-22)

  • Bugfixes

v11.0.0 (2024-10-21)

  • Bugfixes
  • Lazy loading of widget content until visible (GridStackOptions.lazyLoad and GridStackWidget.lazyLoad)
  • Support for Angular Component hosting true sub-grids (that size according to parent) without requring them to be only child of grid-item-content.

v10.3.1 (2024-07-22)

  • Bugfixes

v10.3.0 (2024-06-24)

  • Bugfixes

v10.2.1 (2024-06-24)

  • Bugfixes

v10.2.0 (2024-06-03)

  • Bugfixes
  • You can now press 'Esc' to cancel a move|resize, 'r' to rotate during a drag. added GridStack.rotate() as well

v10.1.2 (2024-03-31)

  • Bugfixes

v10.1.1 (2024-03-04)

  • Bugfixes

v10.1.0 (2024-02-05)

  • Bugfixes
  • Allow cell height in cm and mm units

v10.0.1 (2023-12-11)

  • Bugfixes

v10.0.0 (2023-11-21)

  • Support much richer responsive behavior with GridStackOptions.columnOpts including any breakpoint width:column pairs, or automatic column sizing.
  • disableOneColumnMode, oneColumnSize, oneColumnModeDomSort have been removed

v9.5.1 (2023-11-12)

  • bugfixes

v9.5.0 (2023-10-27)

  • bugfixes
  • add div scale support

v9.4.0 (2023-10-16)

  • bugfixes

v9.3.0 (2023-10-01)

  • bugfixes

v9.2.2 (2023-09-28)

  • bugfixes

v9.2.1 (2023-09-25)

  • bugfix

v9.2.0 (2023-09-11)

  • bugfix

v9.1.1 (2023-09-07)

  • bugfix

v9.1.0 (2023-09-05)

  • bugfix

v9.0.2 (2023-08-30)

  • update & bugfix

v9.0.1 (2023-08-28)

  • update & bugfix

v9.0.0 (2023-08-24)

  • added GridStackOptions.fitToContent and GridStackWidget.fitToContent to make gridItems size themselves to their content (no scroll bar), calling GridStack.resizeToContent(el) whenever the grid or item is resized.
  • added new 'resizecontent' event, and resizeToContentCB and resizeToContentParent vars.
  • fixed inf loop when autoPosition after loading into 1 column, then 2.

v8.4.0 (2023-07-21)

  • feat: attribute DDRemoveOpt.decline to deny the removal of a specific class.
  • fix: dragging onto trash now calls removeWidget() and therefore GridStack.addRemoveCB (for component cleanup)
  • feat: load() support re-order loading without explicit coordinates (autoPosition or missing x,y) uses passed order.

v8.3.0 (2023-06-14)

  • column(N, 'list'|'compact'|...) resizing now support reflowing content as list

v8.2.3 (2023-06-12)

  • bugfixes

v8.2.1 (2023-05-27)

  • fix: make sure removeNode() uses internal _id (unique) and not node itself (since we clone those often)
  • fix: after calling addRemoveCB make sure we don't makeWidget() (incorrectly) a second time
  • break: GridStackWidget.id is now string only (used to be numberOrString) as it causes usage to have to check and cast

v8.2.0 (2023-05-25)

  • feat: makeWidget() now take optional GridStackWidget for sizing
  • fix: make sure GridStack.saveCB is call in removeWidget()
  • feat: angular wrapper: serialize custom data support, and making sure destroy() is called on ng components

v8.1.2 (2023-05-23)

  • module for Angular wrapper

v8.1.1 (2023-05-14)

  • bugfix
  • also further compressed CSS multi column rules (use .gs-# > .grid-stack-item instead of .grid-stack-# > .grid-stack-item)

v8.1.0 (2023-05-07)

  • break: remove GridStackOptions.minWidth obsolete since 5.1, use oneColumnSize instead
  • optimize: CSS files now even 25% smaller (after being halfed in 8.0.0) by removing .grid-stack prefix for anything already gs based, and 3 digit rounding.
  • fix: setupDragIn() signature tweaks (HTMLElement | Document)
  • feat: added GridStackOptions.draggable.cancel for list of selectors that should prevent item dragging

v8.0.0/1 (2023-04-30)

  • package is now ES2020 (TS exported files), webpack all.js still umd (better than commonjs for browsers), still have es5/ files unchanged (for now)
  • removed gs-min|max_w|h attribute generated in CSS or written out as they are never used for rendering, only for initial load. This reduce our column/row CSS in half!
  • removed gs-w='1' and gs-h='1' dom attribute writing since we already have min-width/min-height set, no need to set more attributes.
  • remove 'ui-draggable' and 'ui-resizable' since wasn't used in CSS and we have the -disabled version when off (so we can use not(xyz-disabled)).
  • add: GridStack.saveCB global callback for each item during save so app can insert any custom data before serializing it. save() can now be passed optional callback
  • move: GridStack.addRemoveCB is now global instead of grid option. load() can still be passed different optional callback
  • fix: addGrid() to handle passing an existing initialized grid already
  • break: GridStackOptions.subGrid -> GridStackOptions.subGridOpts. We now have GridStackWidget.subGridOpts vs GridStackNode.subGrid (subclass) rather than try to merge the two at runtime since very different types...
  • tons of improvements for Angular wrapper

v7.3.0 (2023-04-02)

  • support nonce for CSP
  • support nested grids with Angular component demo
  • load() with collision fix
  • autoPosition bug loading from DOM

v7.2.3 (2023-02-03)

  • add opts.draggable.scroll back to disable scrolling. 
  • bugfix

v7.2.0 (2023-01-17)

  • bugfixes

v7.2.0 (2023-01-08)

  • add - init()|initAll() will now load any listed children (what addGrid() already did)
  • add - GridStackOptions.addRemoveCB which is use by frameworks (eg Angular) to dynamically create their gridItem components instead of regular div with class
  • bugfix

v7.1.2 (2022-12-30)

  • add disable/enable are methods now recursive by default
  • add better GridStackEventHandlerCallback spelled out types
  • bugfix

v7.1.0 (2022-10-24)

  • Bugfix
  • Add GridStackEngine.findEmptyPosition()

v7.0.1 (2022-10-15)

  • Bugfix

v7.0.0 (2022-10-10)

  • Create sub-grids on the fly, by dragging items completely over others (nest) vs partially (push) using new flag GridStackOptions.subGridDynamic=true.
  • Add - ability to pause drag&drop collision until the user stops moving - see DDDragOpt.pause (used for creating nested grids on the fly based on gesture).
  • You can now drag sub-grids into other sub-grids

v6.0.3 (2022-10-09)

  • bugfixes

v6.0.2 (2022-09-24)

  • bugfixes

v6.0.1 (2022-08-28)

  • bugfixes

v6.0.0 (2022-08-22)

  • converted previous HTML5 draggable=true based code to simple Mouse Events and Touch mobile support for drag&Drop.
  • removed all jquery-ui related code, and D&D plugging as we only support native events now
  • alwaysShowResizeHandle now support 'mobile' which is the default, making it much easier
  • changed commit() to be batchUpdate(false) to make it easier to turn batch on/off. updated doc. old API remains for now

v5.1.1 (2022-06-17)

  • bugfix

v5.1.0 (2022-05-22)

  • add GridStack.registerEngine() to let user use their own custom layout engine subclass. Thank you [Thomas] for sponsoring it.
  • grid option minWidth is now oneColumnSize to make it clearer, but old field will still work (JS only) for a while
  • fixed restore animation when dragging items
  • updated jquery-ui to latest v1.13.1

v5.0.0 (2022-01-11)

  • add support dragging into and out of nested grids from parents.
  • add new column:'auto' option to size nested grids to their parent grid item column count, keeping items the same size inside and outside.
  • fix nested.html: dragging between sub-grids show items clipped
  • fix dragging between vertical grids causes too much growth, not follow mouse.
  • fix no longer force rows for min-height

v4.4.1 (2021-12-25)

  • Bugfix

v4.4.0 (2021-12-22)

  • add support for IE (new es5 folder)
  • bugfix

v4.3.1 (2021-10-19)

  • fix prevent swap during resize
  • fix save highest resolution in 1 column mode
  • fix resize when padding is large vs cellHeight

v4.3.0 (2021-10-16)

  • you can now swap items of different width if they are the same row/height
  • fix nested grid save inf loop fix

v4.2.7 (2021-09-13)

  • Fixed: Enable passing of DragEvent to gridstack dropped event.
  • Fixed: Layout incorrectly restored when node has a minimum width. 
  • Fixed: addGrid() does not recognize rem cellHeightUnit.

v4.2.6 (2021-07-12)

  • fixed: removable:true working by itself (without needing acceptWidgets:true)
  • fixed: removed drag flicker and scroll issue. 
  • fixed: save(false) will no longer have .content field (removed existing one if present)
  • fixed: save(false, false) now correctly saves nested grids
  • fixed: save(false, true) followed by enable() throws error. we now have new Utils.cloneDeep()

v4.2.5 (2021-05-31)

  • fix for website with JQ droppable('destroy') giving error

v4.2.4 (2021-05-30)

  • fix removable:true working again (broke in 4.x)
  • fix staticGrid(false) will now enable drag in behavior (if set)
  • fix locked item can be user moved/resized again, just not pushed by other nodes (broke in 1.1.1)
  • fix destroy(false) can now re-init properly (doesn't force static grid)

v4.2.3 (2021-05-08)

  • Utils.getScrollParent() -> getScrollElement() rename
  • fix digression on scrolling in v4.2.1

v4.2.2 (2021-04-24)

  • fix mac Safari H5 draggable broken in 4.0.1
  • fix mac Safari page scroll fix

v4.2.1 (2021-04-19)

  • fixed: JQ nested grid drag fix broken in 4.0.3 (but much older underlying issue)
  • fixed: item gs-x:0 not animating fix
  • fixed: resize-scroll issue when grid is not at top of page. Thanks @Manfred-on-github
  • fixed: fix sizing from top/left sides

v4.2.0 (2021-04-12)

  • fixed: scrollbar fix broken in 4.x
  • fixed: addWidget() while in 1 column now remembers original wanted width
  • added: addWidget() now supports nested grids like init/addGrid() does

v4.1.0 (2021-04-08)

  • fixed Can't easily drag widgets below widgets on the bottom border of a grid
  • when dragging an item at the bottom below others to make it easier to insert below.
  • more fix for drag between 2 grids with row / maxRow broken in 4.x
  • fix export symbols .d.ts for gridstack-h5.js | gridstack-jq.js | gridstack-static.js
  • fix correct info for using JQ version and ES6 (tested in Angular app)

v4.0.3 (2021-03-29)

  • fix load after init() broken in 4.x
  • fix drag between 2 grids with row / maxRow broken in 4.x
  • fix drag edge case in/out single grid without acceptWidgets fix broken in 4.x

v4.0.2 (2021-03-28)

  • fix: {handles:'w/sw'} work again in 4.x
  • fix: enableMove(T/F) not working correctly
  • fix helper: myFunction now working for H5 case for dragInOptions & setupDragIn()
  • fix: prevent addGrid() from creating nested div grid if container already is a '.grid-stack' div

v4.0.1 (2021-03-21)

  • fix JQ resize broken
  • fix serialization of nested grid

v4.0.0 (2021-03-20)

  • add drag | resize events while dragging
  • add GridStack.setupDragIn() so user can update external draggable after the grid has been created
  • fixed bugs

v3.3.0 (2021-02-03)

  • big re-write on how cellHeight() works. you can now call it at any time (not just grid init options) including switching to 'auto' or other modes on the fly.
  • fix cellHeight:auto now keeps cell square as window resizes (regressing from 2.x TS conversion). Utils.throttle() works better too (guaranteed to be called last event)
  • new cellHeight:initial which makes the cell squares initially, but doesn't change as windows resizes (better performance)
  • new grid option cellHeightThrottle (100ms) to control throttle of auto sizing triggers
  • fixed: height too small with cellHeight:auto loading in 1 column. Now detect we load at 1 column and size accordingly (default 'auto' could make big 700x700 cells, so explicit px might still be wanted)
  • fixed: loading nested into small size and sizing back up
  • fixed: nested grid resizing fix
  • fixed: H5 resize from left side can move item right

v3.2.0 (2021-01-26)

  • fix website & lib works on mobile. We now compile the latest v1.0.8 jquery.ui.touch-punch into the JQ version (only 2k) so mobile devices (android, iphone, ipad, ms surface, etc...) are supported out of the box. HTML5 version will require re-write to plain mousemove & mobile touchmove instead of drag events in a future release.
  • small optimizations (create placeholder content on the fly, moved more DD code into draggable class)

v3.1.5 (2021-01-24)

  • fix column: N option now sets CSS class
  • fix don't allow drop when grid is full
  • fix easier to drag out/in from below
  • fix cellHeight() not updating CSS correctly
  • fix H5 draggable by actual div handle rather than entire item (let content respond to drag as well)

v3.1.4 (2021-01-12)

  • fix no-drop cursor on windows when dragging within a default grid (no external drag in)
  • fix Safari H5 delay when dropping items

v3.1.3 (2021-01-03)

  • bugfixes

v3.1.2 (2020-12-08)

  • fix dragging into a fixed row grid works better (check if it will fit, else try to append, else won't insert)
  • possible BREAK (unlikely you use engine directly)
  • engine constructor takes Options struct rather than spelling arguments (easier to extend/use)
  • canBePlacedWithRespectToHeight() -> willItFit() like grid method
  • fix maxW does not work as intended with resizable handle "w"
  • fix support all options for new dragged in widgets (read all gs-xyz attributes)
  • fix dragging any grid item content works
  • fix web-component fixes & grid with 0 size initially. (edited)

v3.1.0 (2020-12-05)

  • add new addGrid(parent, opts) to create a grid and load children instead of init() + load(), which is used by load() to supports nested grids creation.
  • save() will now work on nested grids, recursively saving info. added flag to also allow saving the current grid options + children (needed for nested grids) so you can now call new adddGrid() to re-create everything from JSON.
  • fixed: don't call movable()/resizable() on locked items error. 
  • fixed: force typescript 3.6 as 3.7+ has breaking change forcing apps to be at least 3.7 (we only used one tiny feature in newest TS, not worth the incompatibility).

v3.0.0 (2020-11-30)

  • Native HTML5 drag&drop plugin included
  • Fix placeholder not having custom GridStackOptions.itemClass. thanks @pablosichert
  • Fix dragging between 2 grids and back (regression in 2.0.1)
  • Fix load() into 1 column mode doesn't resize back to 12 correctly
  • Fix update(el, opts) re-write to take all GridStackWidget options (not just x,y,width,height) and do everything efficiently.
  • Hiding locked(), move(), resize(), minWidth(), etc... as they just simply call update() which does all the constrain now as well!
  • Del ddPlugin grid option as we only have one drag&drop plugin at runtime, which is defined by the include you use (HTML5 vs jquery vs none)
  • Change attribute data-gs-min-width is now gs-min-w. We removed 'data-' from all attributes, and shorten 'width|height' to just 'w|h' to require less typing and more efficient (2k saved in .js alone!)
  • Also GridStackWidget used in most API width|height|minWidth|minHeight|maxWidth|maxHeight are now shorter w|h|minW|minH|maxW|maxH

v2.2.0 (2020-11-08)

  • add margin option now support multi values CSS format '5px 10px 0 20px' or '5em 10em'
  • add data-gs-static-grid attribute
  • fix class="ui-draggable-disabled ui-resizable-disabled" have been added back to static grid items, so existing CSS rule to style continue working
  • fix getting DOM element by id with number works (api that uses GridStackElement handle more string formats)
  • fix setting marginTop (or any 4 sides) to cause resize to break

v2.1.0 (2020-10-29)

  • fix grid static: true to no longer add any drag&drop (even disabled) which should speed things up, and setStatic(T/F) will now correctly add it back/delete for items that need it only.
  • Also fixed JQ draggable warning if not initialized first
  • add addWidget(opt) now handles just passing a GridStackWidget which creates the default divs, simplifying your code. Old API still supported.
  • add save(saveContent = true) now lets you optionally save the HTML content in the node property, with load() restoring it
  • add GridStackWidget.content now lets you add any HTML content when calling load()/save() or addWidget()
  • add ColumnOptions to column(n, options) for multiple re-layout options, including 'none' that will preserve the x and width, until out of bound/overlap

v2.0.2 (2020-10-06)

  • fix animate to not re-create CSS style each time (should be faster too) and made it default now since so much nicer. pass {animate: false} grid options if you want instant again
  • fix resizable: { handles: ...} forcing alwaysShowResizeHandle behavior

v2.0.1 (2020-09-27)

  • lots of bugs fixes

v2.0.0 (2020-09-05)

  • re-write to native Typescript, removing all JQuery from main code and API (drag&drop plugin still using jqueryui for now)
  • add getGridItems() to return list of HTML grid items
  • add {dragIn | dragInOptions} grid attributes to handle external drag&drop items
  • add save() and load() to serialize grids from JSON, saving all attributes (not just w,h,x,y)
  • add margin to replace verticalMargin which affects both dimensions in code, rather than one in code the other in CSS.
  • You can now have perfect square cells (default)
  • fix #1299 many columns round-off error
  • fix #1102 loose functionality when they are moved to a new grid
  • add optional params to removeWidget() to have quiet mode (no callbacks)

v1.2.1 (2020-09-05)

  • Enable the UMD behavior for bundlers compatibility

v1.2.0 (2020-05-18)

  • fix domAttr is not defined
  • adds styleInHead option to allow for selecting older behavior (adding STYLE element to HEAD element instead of parentNode)
  • update jquery to v3.5.1

v1.1.2 (2020-05-18)

  • fixed: staticGrid no longer disable oneColumnMode
  • fixed: options broken with ember hash helper - thanks @btecu
  • fixed: don't remove item from another grid
  • fixed: init() clones passed options so second doesn't affect first one
  • fixed: addWidget() ignores data attributes

v1.1.1 (2020-04-13)

  • jQuery was removed from the API and dependencies (initialize differently, and methods take/return GridStack or HTMLElement instead of JQuery).
  • Updated Doc accordingly.

v0.6.4 (2020-02-18)

  • optimized change callback to save original x,y,w,h values and only call those that changed
  • more bugs fixed

This awesome jQuery plugin is developed by gridstack. For more Advanced Usages, please check the demo page or visit the official website.