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

Drag and Drop Grid Responsive & Fluid Layout with jQuery
Drag and Drop Grid Responsive & Fluid Layout with jQuery

Gridstack.js is a Gridster-inspired JavaScript fluid layout widget/grid layout widget plugin that allows you to dynamically and responsively rearrange grid items via drag and drop styling on a seamless page layout.

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 (v2.0.0+)

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/dist/gridstack.min.css" />
<script src="https://cdn.jsdelivr.net/npm/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,

    // turns animation on
    animate: false,

    // amount of columns and rows
    column: 12,
    row: 0,

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

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

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

    // cell height unit
    cellHeightUnit: 'px',

    // margin
    margin: 10,
    marginUnit: 'px',

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

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

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

    // specify the class of items that can be dragged into the grid
    dragIn: false,
    dragInOptions : {
      helper: 'clone',
      handle: '.grid-stack-item-content',
      appendTo: 'body'
    },

    // the type of engine to create (so you can subclass)
    engineClass: 'GridStackEngine',

    // 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,
    removableOptions: {
      accept: 'grid-stack-item'
    },

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

    // disables the oneColumnMode when the grid width is less than minW
    disableOneColumnMode: 'false',
});

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

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

// 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
});

Live Demo

See the Pen Untitled by Plugin JS (@teguhsigit) on CodePen.

File Info

File Name :
gridstack.js-master.zip
Size :
312.82KB
Site Download :
Github.com
Official Website:
Go to website
License:
MIT
Previous Post Next Post