Items deferred from the June 2026 code-quality pass. Tackle in order; each builds on the previous.
Why: tsconfig.json runs with strict: false and noImplicitAny: false, hiding a whole class of bugs from both the compiler and consumers who rely on the published .d.ts declarations.
Steps:
- Enable
"strictNullChecks": truefirst (lowest noise). Fix the resulting errors — most are already nullable but were silently untyped. - Enable
"noImplicitReturns": trueand"noImplicitAny": true. The majority of remaining issues will be in the drag-and-drop internals (dd-draggable.ts,dd-resizable.ts) and the engine. - Finally set
"strict": trueto catch the rest (strict function types, strict property init, etc.). - Remove the per-file
// eslint-disable-next-line @typescript-eslint/no-explicit-anysuppressions as each file is cleaned up.
Estimated scope: ~50-80 type errors once strictNullChecks is on, mostly in gridstack.ts and the DD layer.
Why: The single GridStack class has grown to cover CSS/cell-height management, responsive/column layout, drag-drop wiring, serialization, and the public API. This makes it hard to navigate and test in isolation.
Proposed split:
| New file | Responsibility |
|---|---|
gridstack-css.ts |
cellHeight(), _initMargin(), _updateStyles(), CSS variable management |
gridstack-column.ts |
column(), checkDynamicColumn(), _columnLayouts, responsive breakpoint logic |
gridstack-dnd.ts |
_setupAcceptWidget(), _setupRemoveDrop(), _onStartMoving(), _onEndMoving(), drag/resize event wiring |
gridstack-serialize.ts |
save(), load(), _readAttr(), _writePosAttr() |
gridstack.ts |
Public API surface + constructor, thin delegation to the above |
Approach: Use mixin-style imports or prototype extension (same pattern the DD layer already uses) so the public class shape is unchanged and no semver break occurs.
Why: The build currently combines Grunt + webpack + tsc. The React/Vue demo apps already use Vite. Consolidating onto a single bundler would simplify CI, reduce dependency surface, and speed up the build.
Proposed target: Rollup (or Vite's library mode) for the core src/ library, keeping the framework wrappers on their own build.
Steps:
- Audit
Gruntfile.js— identify what it does beyond whattsc+ webpack already cover (likely banners and legacy UMD output). - Replace webpack config with a Rollup config producing ESM + CJS + UMD outputs (same as today).
- Remove
Gruntfile.jsand thegruntdependency once the Rollup outputs match. - Update
package.json"build"script. - Verify the demo apps still work (
yarn build:ng,yarn build:react).
Why: Grid items are plain <div> elements with no ARIA roles or keyboard interaction, making the library unusable for accessibility-sensitive dashboards.
Minimum viable work:
- Add
role="grid"to the container androle="gridcell"(or"group") to items. - Emit
aria-grabbed="true/false"during drag. - Document how to layer keyboard-move support on top (arrow keys to move focused item, or provide an optional built-in mode).
Why: This method creates, appends, reads, and removes a probe <div> on every call to calculate CSS transform scale/offset. If called during drag/resize events it triggers repeated forced layout (reflow).
Fix: Cache the result on the grid element (or dragTransform property) and invalidate only when a ResizeObserver or transform change is detected, rather than recomputing each drag tick.