Responsive & Fluid Drag-and-Drop Grid Layout with jQuery - gridstack.js

Responsive & Fluid Drag-and-Drop Grid Layout with jQuery - gridstack.js
File Size: 355 KB
Views Total: 94276
Last Update:
Publish Date:
Official Website: Go to website
License: MIT

Gridstack.js is a vanilla JavaScript widget/grid layout plugin inspired by Gridster that allows you to dynamically and responsively rearrange grid items through drag and drop.

Note: The library now works as a Vanilla JavaScript plugin. You can also download the jQuery Version here for jQuery projects.

More features:

  • Also supports touch events.
  • Resizable grid items.
  • Supports nested grid items.
  • Compatible with Bootstrap 3/4 framework.
  • No jQuery required (v1.0.0+)

View more:

Table Of Contents:

Basic Usage (Vanilla JS Version):

1. Install & Download the package.

# Yarn
$ yarn add gridstack

$ npm install gridstack --save

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

<link rel="stylesheet" href="[email protected]/dist/gridstack.min.css" />
<script src="[email protected]/dist/gridstack.all.js"></script>

3. Insert optional grid items to the Grid Stack container.

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

4. Initialize the plugin and done.

var grid = GridStack.init();

5. All options, methods, and events are same as the jQuery version. Keep scrolling down to learn more.

Basic Usage (jQuery Version):

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

<!-- Local -->
<link href="/path/to/gridstack.css" rel="stylesheet" />
<!-- Or From A CDN -->
<link rel="stylesheet" href="[email protected]/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="[email protected]/dist/gridstack.all.js"></script>
<!-- Polyfill for old IE -->
<script src="gridstack.poly.js"></script>

3. Create a sample draggable grid layout as follows.

  • data-gs-animate: turns animation on (for grid)
  • data-gs-column: amount of columns (for grid)
  • data-gs-max-row: maximum rows amount, defaults to 0 (for grid)
  • data-gs-current-height: current rows amount (for grid)
  • data-gs-id: unique ID (for item)
  • data-gs-x, data-gs-y: element position (for item)
  • data-gs-width, data-gs-height: element size (for item)
  • data-gs-max-width, data-gs-min-width, data-gs-max-height, data-gs-min-height: element constraints (for item)
  • data-gs-no-resize: disable element resizing (for item)
  • data-gs-no-move: disable element moving (for item)
  • data-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)
  • data-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)
  • data-gs-resize-handles: resize handles (for item)
<div class="grid-stack" data-gs-width="12">
  <div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="4" data-gs-height="2">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="4" data-gs-y="0" data-gs-width="4" data-gs-height="4">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="8" data-gs-y="0" data-gs-width="2" data-gs-height="2" data-gs-min-width="2" data-gs-no-resize="yes">
    <div class="grid-stack-item-content"> <span class="fa fa-hand-o-up"></span> Drag me! </div>
  <div class="grid-stack-item" data-gs-x="10" data-gs-y="0" data-gs-width="2" data-gs-height="2">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="0" data-gs-y="4" data-gs-width="2" data-gs-height="2">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="2" data-gs-y="4" data-gs-width="2" data-gs-height="4">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="8" data-gs-y="4" data-gs-width="4" data-gs-height="2">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="0" data-gs-y="6" data-gs-width="2" data-gs-height="2">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="4" data-gs-y="6" data-gs-width="4" data-gs-height="2">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="8" data-gs-y="6" data-gs-width="2" data-gs-height="2">
    <div class="grid-stack-item-content"></div>
  <div class="grid-stack-item" data-gs-x="10" data-gs-y="6" data-gs-width="2" data-gs-height="2">
    <div class="grid-stack-item-content"></div>

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

$(function () {
    column: 12

5. All possible options and defaults available.


  // 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,

  // one cell height
  cellHeight: 60,

  // vertical gap size
  verticalMargin: 20,

  // 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.

// Relayout grid items to reclaim any empty space.

// Gets current cell height.

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

// Gets current cell width.

// Returns current vertical margin value.

// 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.

// set/get floating widgets

// 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.

// 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

// 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.

// 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.

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

// Destroy the instance
// detachGrid - if false nodes and grid will not be removed from the DOM

// Enables/disables the plugin

// 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 =;

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

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

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

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

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

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

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


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.