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

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

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 framework.
  • No jQuery required (v5.1.1+)

View more:

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

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

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.