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 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:
- 10 Best Grid Layout Systems In JavaScript And CSS
- 10 Best jQuery/JavaScript Masonry Layout Plugins
- 10 Best Advanced Drag And Drop Plugins In JavaScript
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-width,gs-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.











