gridstack.js: the layout engine under your draggable dashboard
Build interactive dashboards in minutes.
At a glance
- What is it?
- A dependency-free TypeScript library that turns ordinary HTML into a drag and resize grid, shipped with React, Angular and Vue wrappers and a long list of breaking majors.
- Who is it for?
- gridstack.js earns its place when the dashboard layout has to be user-editable and saved, because that is the part CSS grid cannot do for you. The costs are real and worth naming: it is a layout engine with no widgets and no persistence, you own saving the serialized layout, and every major version has carried breaking changes, with v14 replacing the float option with a mode setting.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 11 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A grid of positioned DOM nodes rather than a drawn canvas
gridstack.js is a layout engine, not a charting library. It takes a container element, turns its children into cells, and keeps each cell's x, y, width and height in sync with what a user does by dragging or resizing it. The repository describes itself as a mobile-friendly modern pure TypeScript library for dashboard layout and creation with no external dependencies, and that last part is literal rather than marketing: lodash was removed in v0.5, the jQuery API in v1, and v3 was a complete HTML5 rewrite.
The mechanism matters more than the tagline. Layout is done with CSS column based percentages rather than absolute pixel positions, which is why the README insists on including gridstack.min.css next to the script. The library writes classes and CSS custom properties onto the item elements and reads geometry back from the browser, so your widget content stays ordinary HTML inside a cell. That is a different bargain from a canvas dashboard, where your content becomes a list of draw calls, and it is why a gridstack cell can hold a table, an iframe or a live chart without special treatment.
The project states its lineage plainly, describing itself as inspired by the no longer maintained gridster. The distance between the two is mostly about event handling and mobile input: v6 moved to native mouse and touch events and dropped the jQuery UI version that older forks still depend on.
Installing the package and including the stylesheet
A grid without its CSS is a stack of divs, so the README treats installation as two steps.
yarn add gridstack
// or
npm install --save gridstackFor an ES6 or TypeScript project, the stylesheet is imported beside the module rather than linked in HTML:
import 'gridstack/dist/gridstack.min.css';
import { GridStack } from 'gridstack';For a plain page, the README points at the combined bundle, and the -all.js suffix matters because the single file exports several module formats side by side:
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
<script src="node_modules/gridstack/dist/gridstack-all.js"></script>There is a documented escape hatch for old browsers. The README offers an es5 build plus a polyfill, and it is unusually candid about browser support history: Internet Explorer was dropped in v2, restored in v4.4 by an external contributor, and dropped again in v12 because a CSS variable was needed. The author's stated position is that they have no interest in testing obsolete browsers, so the es5 path may break again without much warning.
Filling a grid dynamically, from data, or from markup
There are three ways to put content on the grid, and the choice is mostly about who owns the layout state.
The dynamic route calls init on the container and then adds widgets by object:
var grid = GridStack.init();
grid.addWidget({w: 2, content: 'item 1'});The serialized route is the one you want for a saved dashboard, because the array is the layout and can be round-tripped to your own storage:
const serializedData = [
{x: 0, y: 0, w: 2, h: 2},
{x: 2, y: 3, w: 3, content: 'item 2'},
{x: 1, y: 3}
];
grid.load(serializedData);The third route writes the markup first and initialises afterwards, which suits server-rendered pages. Cell attributes go straight on the element:
<div class="grid-stack">
<div class="grid-stack-item">
<div class="grid-stack-item-content">Item 1</div>
</div>
<div class="grid-stack-item" gs-w="2">
<div class="grid-stack-item-content">Item 2 wider</div>
</div>
</div>Note what the library does not do in any of the three cases. It does not fetch your data, render your widgets or persist the result. Reading the array back out and storing it is your code, which is the honest division of labour here.
What v14 changed and why the major number keeps moving
v14.0.0 was published on 2026-09-21, the same calendar day as the repository's most recent push, and its notes call out two large changes. The old `float` boolean is replaced by a `mode` setting that accepts top, float, list or compact, where list mode re-flows items in sequential order like a sortable list instead of pushing everything else down. The second change adds a `cellHeight: 'fill'` option so rows divide the whole container height rather than taking a fixed cell size.
That pattern is not a one-off. The README carries a migration section for every major version from v0.6 through v14, and the recent releases show the same churn in smaller form: v13.2.0 removed `printMode` and added `PrintOptions.mode` in the same release, v13.3.0 added `PrintOptions.breakInside` and a print-avoid-break class, and v12 is where Internet Explorer support ended. Reading a major version here is not ceremony, because option names you saved against a year ago may be gone.
The upside of a project this willing to break its own API is that the alternative, gridster, is simply not maintained. Neither choice is free.
React, Angular and Vue wrappers kept in the same tree
The repository tree shows the shape of the effort: src/ for the core engine, then angular/, react/ and vue/ directories with their own build steps, doc/ for the generated API, demo/ for roughly two dozen example pages, and both e2e/ and spec/ for tests. The build script in package.json chains the core build through the three framework builds and then regenerates the documentation, which tells you the wrappers are first-class rather than community afterthoughts.
The wrappers are not the only integrations listed. For Ember the README points at ember-gridstack, for AngularJS at gridstack-angular, and for knockout it points at a demo using a component. What is refreshing is the honesty about one of them: the Angular 9 entry is described as a very old v0.3 instance, recommended for concept only if you want a directive instead of a component, and explicitly not vetted by the maintainer.
The demo directory is worth browsing before writing any code. Files named list.html, nested.html, nested_constraint.html, locked.html, mobile.html, print.html, custom-engine.html and cell-height.html map almost one to one onto the features the release notes keep changing.
Where gridstack stops and plain CSS grid takes over
Native CSS grid is the honest alternative, and it wins in one specific case: when the layout is responsive by breakpoint and nobody needs to drag anything. CSS grid gives you reflow, auto-placement and responsive tracks with no JavaScript at all. What it cannot give you is a user picking a cell size and having that choice persist.
gridstack's own boundary is easier to state. It draws no charts, binds no data, and stores nothing. Every dashboard built on it needs a second system for what goes inside the cells and a third for where the serialized layout is kept, and the library's value is entirely in the third dimension, which is user editing. A monitoring view that is the same for every user is a case where plain CSS grid or a flex layout is less work.
The testing setup is a fair signal of how seriously the geometry work is taken. The tree carries vitest.config.ts, vitest.setup.ts, playwright.config.ts, a protractor config still in place from the older era, and a TESTING.md at the root, with e2e/ holding browser-level cases. The README also states that the markdown API documentation is regenerated with the code, which means it covers unreleased changes as well as the published version, a small but real advantage when you are reading the docs and the code side by side.
Editorial conclusion
gridstack.js earns its place when the dashboard layout has to be user-editable and saved, because that is the part CSS grid cannot do for you. The costs are real and worth naming: it is a layout engine with no widgets and no persistence, you own saving the serialized layout, and every major version has carried breaking changes, with v14 replacing the float option with a mode setting. Start with grid.load() on a static array and the doc/API.md file, which the README says is regenerated with the code, then read the migration notes for your target version before shipping a layout that users have already saved.
Frequently asked questions
Does gridstack.js depend on jQuery?
No. The README records that the jQuery API was removed in v1 and that v3 was a complete HTML5 rewrite, with v6 moving to native mouse and touch events and dropping the jQuery UI version. Older forks in the wild still assume jQuery, so check which version you are installing before copying a snippet from an old tutorial.
How do I save and restore a gridstack layout?
Read the layout back out as an array of cell objects and store it wherever your own app keeps state, then hand the same array to load() on the next visit. The README demonstrates loading a serialized array with x, y, w and h values, which is the shape you persist. The library stores nothing itself.
Is there an official React or Vue wrapper for gridstack?
Yes, and they live in the same repository under react/ and vue/, with build:react and build:vue scripts in package.json alongside an angular/ directory. The README also lists third-party wrappers for Ember, AngularJS and knockout, but warns that the Angular 9 option is an old v0.3 instance it has not vetted.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gridstack-gridstack-js)