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

File Size: | 707 KB |
---|---|
Views Total: | 99730 |
Last Update: | |
Publish Date: | |
Official Website: | Go to website |
License: | MIT |
Gridstack.js is a vanilla JavaScript widget/grid layout plugin inspired by Gridster that allows you to dynamically and responsively rearrange grid items through drag and drop.
Note: The library now works as a Vanilla JavaScript plugin. You can also download the jQuery Version here for jQuery projects.
More features:
- Also supports touch events.
- Resizable grid items.
- Supports nested grid items.
- Compatible with Bootstrap 3/4 framework.
- No jQuery required (v2.0.0+)
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/[email protected]/dist/gridstack.min.css" /> <script src="https://cdn.jsdelivr.net/npm/[email protected]/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 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, // 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, 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, // 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'}, // specify the class of items that can be dragged into the grid dragIn: false, dragInOptions : { revert: 'invalid', handle: '.grid-stack-item-content', scroll: false, appendTo: 'body' }, // 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, // 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.
// Creates a new widget. grid.addWidget(el, { // options x, y, width, height, autoPosition, minWidth, maxWidth, minHeight, maxHeight, id, locked, noResize, noMove, resizeHandles }); // create a grid and load children instead of init() + load() grid.addGrid(parent, opts); // 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(); // Set/get the number of columns in the grid // Require gridstack-extra.min.css grid.column(column, doNotPropagate) // Set the top/right/bottom/left margin between grid item and conten grid.margin(value: numberOrString); // Finishes batch updates. Updates DOM nodes. You must call it after batch_update. grid.Commit(); // Set/get floating widgets grid.float(val); // Get current cell height grid.getCellHeight(); // 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); // Return list of GridItem HTML dom elements (excluding temporary placeholder) grid.getGridItems(); // Return 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) // 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); // Return 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). grid.save(true/false);
7. 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('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('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/[email protected]/dist/gridstack.min.css" />
2. Include the jQuery Gridstack.js plugin and other required resources at the end of the document.
<!-- Dependencies --> <script src="/path/to/cdn/jquery.min.js"></script> <script src="/path/to/cdn/jquery-ui.min.js"></script> <script src="/path/to/cdn/jquery.ui.touch-punch.min.js"></script> <!-- jQuery Gridstack.js --> <script src="gridstack.all.js"></script> <!-- Or from a CDN --> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gridstack.all.js"></script> <!-- Polyfill for old IE --> <script src="gridstack.poly.js"></script>
3. Create a sample draggable grid layout as follows.
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)); // 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:
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.