Excel-like CRUD Data Grid Library - Handsontable

File Size: 11.4 MB
Views Total: 79089
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
Excel-like CRUD Data Grid Library - Handsontable

handsontable is a powerful, flexible, feature-rich, Excel-like CRUD data grid/table library for JavaScript, Angular, React, and Vue.js.

Key features:

  • Data filtering.
  • Data sorting.
  • Data formatting.
  • Insert/remove/edit/resize columns.
  • Cell editing.
  • Fixed headers & columns.
  • Custom context menu.
  • Custom dropdown menu.
  • Collapsible columns.
  • Export to CSV.
  • Calculations.
  • Copy to clipboard.
  • Keyboard navigation.
  • And much more.

You might also like:


$ npm install handsontable --save

Basic Usage

1. Download and include the Handsontable library on the page.

<!-- from local -->
<script src="dist/handsontable.full.min.js"></script>
<link href="dist/handsontable.full.min.css" rel="stylesheet" />
<!-- from cdn -->
<script src="https://cdn.jsdelivr.net/npm/handsontable@latest/dist/handsontable.full.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/handsontable@latest/dist/handsontable.full.min.css" rel="stylesheet" />

2. Create a placeholder element to place the data grid.

<div id="dataTable"></div>

3. Define the data to be presented in the data grid.

const data = [
      ["", "Kia", "Nissan", "Toyota", "Honda"],
      ["2008", 10, 11, 12, 13],
      ["2009", 20, 11, 14, 13],
      ["2010", 30, 15, 12, 13]

4. Initialize the library and render a basic data grid on the page.

var placeholder = document.getElementById('dataTable');
var myDataGrid = new Handsontable(placeholder, {
    data: data,

5. Click here to see the full options to customize the data grid.

6. Handsontable provides a fast way to provide configuration options for the entire table, including its columns and particular cells.

var placeholder = document.getElementById('dataTable');
var myDataGrid = new Handsontable(placeholder, {
    columns: [
      {readOnly: false},
    cells: function(row, col, prop) {
      var cellProperties = {};

      if (row === 0 && col === 0) {
        cellProperties.readOnly = true;

      return cellProperties;


v14.3.0 (2024-04-16)

  • Added new feature, Navigation within selection and edit cells within a range 
  • Updated dependencies based on npm audit, most notably we upgraded to angular
  • Fixed bugs

v14.2.0 (2024-03-06)

  • Added a new Handsontable hook, beforeBeginEditing, to conditionally control when to allow cell editing. 
  • Added the ability to prevent viewport scrolling by using two existing Handsontable hooks: beforeViewportScrollVertically and beforeViewportScrollHorizontally. 
  • Added undo-and-redo support for column moving. 
  • Added a new Filters plugin hook: modifyFiltersMultiSelectValue. Now, filtered values lists will show the formatted numeric value, not the raw data.
  • Improved the viewport scroll behavior after clicking on a cell.
  • Improved the response of checkboxes to double-clicks.
  • Improved the way checkbox cells react to pressing Space or Enter.
  • Improved the type inference of the propToCol() method. 
  • React: Improved React portal caching. 
  • Removed versioned Handsontable examples and their GitHub publishing workflow.
  • Fixed bugs.

v14.1.0 (2024-01-16)

  • Added a new configuration option, renderAllColumns, which lets you disable column virtualization for improved accessibility. 
  • Added a dedicated renderer (DropdownRenderer) and validator (DropdownValidator) for the dropdown cell type. 
  • Added support for the Tab key in the select editor (selectEditor).
  • Improved how undoing changes affects the viewport. Now, when you undo a change, the view automatically scrolls back to the changed area. 
  • Improved how pasting data affects the viewport. Now, even when the size of the pasted data is larger than the viewport, the viewport stays in place.
  • Improved how removing a row or column affects the selection. Now, when you remove a row or column, the selection moves to the nearest visible row or column. 
  • Improved TypeScript definitions for multiple plugins. 
  • Improved TypeScript definitions for the core modules.
  • Improved TypeScript definitions for the CellCoords and CellRange classes.
  • Improved TypeScript definitions for the CustomBorders plugin. 
  • React: Improved support for SSR frameworks. 
  • Fixed bugs.

v14.0.0 (2023-11-30)

  • Added multiple keyboard shortcuts.
  • Added ARIA tags to various elements of the table to improve screen reader compatibility.
  • Added the ability to navigate the headers with the keyboard by introducing a new navigableHeaders option along with other changes.
  • Added the ability to traverse the grid within a webpage using the TAB key and introduced a new tabNavigation option. 
  • Added a new beforeSelectionHighlightSet hook that allows modifying logical selection coordinates before they are applied to the rendering engine.
  • Implemented the select renderer and cell type.
  • Added an accessibility demo for javascript and React.
  • Added handsontable and date renderers for their respective cell types to allow adding the a11y attributes. 
  • Added new beforeColumnWrap and beforeRowWrap hooks.
  • Breaking change: Changed the way the table reacts to using the "select all cells" methods and shortcuts.
  • Breaking change: Changed the colors of the invalid cells and the arrow buttons of the autocomplete-typed cells.
  • Breaking change: Improved the navigation and accessibility of the Filtering Dropdown Menu.
  • Breaking change: Changed the way Handsontable handles focus by focusing the browser on cell elements. Introduced a new imeFastEdit option to minimize the negative effects affecting the "fast edit" feature for the IME users.
  • Improved the keyboard navigation for the context and dropdown menus and added a new forwardToContext option to the ShortcutManager.
  • Extended the Core's scrollViewportTo method to allow disabling of cell auto-snapping.
  • Upgraded the monorepo to utilize Node 20. 
  • Improved DX by adding an exception to be thrown when trying to activate a shortcut context that has been not yet registered. 
  • Improved the performance of the table for cases when the table is hidden.
  • Updated the TypeScript definitions.
  • Changed the default styling of the "OK" button in the Filtering Dropdown when it's focus.
  • Bugfixes

v13.1.0 (2023-09-01)

  • Optimized the transpilation process of the distribution files.
  • Updated the internal monorepo scripts to utilize Node 20.
  • Fixed bugs.

v13.0.0 (2023-06-23)

  • Added support for Angular 16.
  • React, Angular, Vue 2, Vue 3: Changed Handsontable's policy toward older versions of supported frameworks. From now on, Handsontable supports only those versions of any supported frameworks that are officially supported by their respective teams. Dropping Handsontable's support for any older framework versions won't be treated as a breaking change. 
  • Changed the order in which three hooks are executed: now, the beforeChange hook is fired before the afterSetDataAtCell and afterSetDataAtRowProp hooks.
  • Changed the margins of the context menu in the RTL layout direction. 
  • Dropped support for Angular 13 and lower. From now on, Handsontable supports only those versions of Angular that are officially supported by the Angular team: currently, it's 14-16. However, Handsontable 13.0.0 was thoroughly tested and, to the best of our knowledge, works correctly with versions down to Angular 12.
  • Removed the deprecated beforeAutofillInsidePopulate hook.
  • Removed the deprecated getFirstNotHiddenIndex method. Instead, use the getNearestNotHiddenIndex() method.
  • Removed the deprecated parameters of the alter() method: insert_row and insert_col. Instead, use the following parameters: insert_row_above, insert_row_below, insert_col_start, and insert_col_end. 
  • Removed the deprecated parameters of the populateFromArray() method: direction and deltas. 
  • Fixed an issue where the "Read only" icon of the context menu displayed incorrectly in the RTL layout direction.

v12.4.0 (2023-05-23)

  • Added two new Handsontable hooks, afterColumnSequenceChange and afterRowSequenceChange, which are fired after changing the order of columns or rows, respectively. 
  • Bugfixes.

v12.3.3 (2023-03-28)

  • Added a new guide: Rows sorting.
  • Bugfixes.

v12.3.2 (2023-03-23)

  • Added a Chinese (zh-CN) translation of the "Copy with headers" feature.
  • Bugfixes.

v12.3.1 (2023-02-06)

  • Added a Japanese translation of the "Copy with headers" feature.
  • Removed the two-week delay in showing the console warning about license expiration.
  • Bugfixed

v12.3.0 (2022-12-14)

  • Added a new feature that lets you copy the contents of column headers by using 3 new context menu options: "Copy with headers", "Copy with group headers", and "Copy headers only".
  • Added 4 new API methods for copying column headers programmatically: copyCellsOnly(), copyWithColumnHeaders(), copyWithAllColumnHeaders(), and copyColumnHeadersOnly(). 
  • Added missing TypeScript definitions of the CellCoords and CellRange classes, which are used in the arguments of some of the APIs.
  • Added missing TypeScript definitions for the following Handsontable hooks: beforeColumnFreeze, afterColumnFreeze, beforeColumnUnfreeze, and afterColumnUnfreeze.

v12.2.0 (2022-10-24)

  • Added a new feature that lets you add rows and columns at a specified position. Now, the alter() method takes 4 new parameter values: insert_row_above, insert_row_below, insert_col_start, and insert_col_end. The insert_row and insert_col parameters are marked as deprecated.
  • Fixed bugs.
  • Removed a type definition for a non-existing method, translateRowsToColumns().

v12.1.3 (2022-09-22)

  • Removed a custom stable sorting implementation in favor of the built-in sorting algorithm.
  • Removed type definitions for non-existing methods rowOffset and colOffset and a non-existing hook modifyRowSourceData.
  • Bugfixed

v12.1.2 (2022-07-09)

  • Changed the version of the Moment.js dependency from 2.29.3 to 2.29.4, in reaction to a recently-found Moment.js security vulnerability. The vulnerability did not affect a correct configuration of Handsontable.
  • Vue: Freezed the version of the Vue framework that is used in our build chain to ~2.6. This shouldn't affect apps that use Vue 2.7+.

v12.1.1 (2022-07-07)

  • Angular: Fixed an issue where the installation of @handsontable/angular package failed for versions of Angular other than 9

v12.1.0 (2022-06-28)

  • Added smoother row and column moving when some row or columns are hidden.
  • Added getNearestNotHiddenIndex(), a new method that finds the visual index of the nearest not-hidden row or column and works even with large numbers of hidden rows or columns. The previous method, getFirstNotHiddenIndex(), still works, but is marked as deprecated.
  • Added a Czech translation.
  • Added a Serbian translation.
  • Added new hooks: beforeColumnFreeze, afterColumnFreeze, beforeColumnUnfreeze, and afterColumnUnfreeze.
  • Replaced HTML entities appearing in Handsontable's license texts with canonical counterparts.
  • Updated the Pikaday optional dependency to 1.8.2, to let Handsontable work with Parcel 2 without errors.
  • React: Changed the wrapper's lifecycle methods, to let Handsontable work with React 17+ without warnings.
  • Angular: Moved the @angular/core dependency to peer dependencies.
  • Bugs Fixed

v12.0.1 (2022-05-16)

  • Bugfixes

v12.0.0 (2022-04-28)

  • Added ShortcutManager, a new API for customizing keyboard shortcuts.
  • Added support for right-to-left (RTL) languages, introducing a new configuration option: layoutDirection.
  • Added an Arabic translation.
  • Added a new configuration option: fixedColumnsStart.
  • Added a new keyboard shortcut (Ctrl/Cmd + Enter) for filling the selected range of cells with the value of the active cell.
  • Added support for the Home and End keys inside cell editors, for moving the cursor to the beginning or end of the text. 
  • Added support for the latest Node LTS version.
  • Breaking change: Changed how updateSettings() handles data updates, to improve performance and the consistency of user experience. Now, when provided with a new data object, updateSettings() updates the data without resetting any states.
  • Breaking change: Changed how updatePlugin() reacts to updateSettings() calls, to improve performance and the consistency of user experience. Now, calls to updateSettings() update a plugin's state only when the options object contains a configuration option that's relevant to that particular plugin.
  • Breaking change: Changed the order of execution for two hooks: now, beforeKeyDown is properly fired before afterDocumentKeyDown. 
  • Breaking change: Changed how default keyboard shortcuts are defined, to improve keyboard navigation consistency. Most of the shortcuts did not change and are now properly documented in the keyboard shortcuts guide. However, some shortcuts that were not defined explicitly, and were not listed in the documentation, don't work anymore (e.g., Enter opens a cell's editor, but Ctrl + Enter doesn't). This change doesn't affect custom keyboard shortcuts.
  • Breaking change: Split a cross-platform modifier key (Ctrl/Cmd) into two separate keys, to improve keyboard navigation consistency. Now, the Cmd key triggers actions on macOS where the Ctrl key triggers actions on Windows. For example, on macOS, Ctrl + A doesn't work anymore: Cmd + A is used instead. 
  • Breaking change: Changed the actions of the following keyboard shortcuts, to match the usual spreadsheet software behavior, and provide a more intuitive user experience: Ctrl/Cmd + ↑, Ctrl/Cmd + Shift + ↑, Ctrl/Cmd + ↓, Ctrl/Cmd + Shift + ↓, Ctrl/Cmd + ←, Ctrl/Cmd + Shift + ←, Ctrl/Cmd + →, Ctrl/Cmd + Shift + →, Home, Ctrl/Cmd + Home, End, Ctrl/Cmd + End, Shift + Page Up, and Shift + Page Down. #9363 #9364 #9365
  • Changed two scripts of the main Handsontable workspace (./), to speed up the build process: now, the npm run build and npm run test scripts don't build or test the Handsontable examples (./examples). 
  • Changed the version of the Moment.js dependency from 2.24.0 to 2.29.3, in reaction to a recently-found Moment.js security vulnerability that did not directly affect Handsontable. 
  • Changed the version of the HyperFormula optional dependency from ^1.2.0 to ^2.0.0.
  • Fixed bugs.

v11.1.0 (2022-01-14)

  • Added updateData(), a new method that allows for replacing Handsontable's data without
  • resetting the states of cells, rows and columns. 
  • Vue: Added Vue 3 support, by introducing a new wrapper.
  • Updated the TypeScript definition of the setDataAtCell() method. 
  • Extended Handsontable's GitHub Actions workflow, to allow for deploying code examples to GitHub Pages.
  • Fixed bugs.

v11.0.1 (2021-11-18)

  • Fixed bugs

v11.0.0 (2021-11-17)

  • Added TypeScript definition files for Handsontable's modularized version.
  • Vue: Added support for modularization to the Vue wrapper. 
  • React: Added support for modularization to the React wrapper.
  • Angular: Added support for modularization to the Angular wrapper. 
  • Added a new package entry point that allows importing built-in modules in one function call:
  • import { registerAllEditors, registerAllRenderers, registerAllValidators, registerAllCellTypes, registerAllPlugins } from 'handsontable/registry'. 
  • Added a new locale option, to properly handle locale-based data.
  • Added a GitHub Actions workflow that covers testing Handsontable and the wrappers.
  • Added new direction helpers (internal API) that lay ground for future RTL support.
  • Changed how the populateFromArray() method works with its method argument set to shift_down or shift_right. #888 (Breaking change)
  • Moved the entire Handsontable package to its own, new subdirectory: ./handsontable. 
  • Replaced the license files with updated versions. 
  • Fixed bugs

v10.0.0 (2021-09-30)

  • Unified the naming and description of the fourth argument, controller, for selection manipulation in the beforeOnCellMouseDown and beforeOnCellMouseOver hooks.
  • Changed what the beforeRender and afterRender hooks are, and when they are triggered. Added two new hooks: beforeViewRender and afterViewRender. 
  • Changed the optional HyperFormula dependency from 0.6.2 to ^1.1.0, which introduces breaking changes for the Formulas plugin users. 
  • Changed the default values for the rowsLimit and columnsLimit options of the CopyPaste plugin.
  • Added a default font family, size, weight and color.
  • Changed the autoWrapRow and autoWrapCol options` default values from true to false. 
  • Improved the performance of the getCellMeta() method. 
  • Improved the documentation and TypeScript definition of the selectOptions option. 
  • Improved the arguments forwarding in the hooks
  • Bugs Fixed

v9.0.2 (2021-07-28)

  • Fixed an issue where the validator function was called twice when the Formulas plugin was enabled.

v9.0.1 (2021-06-17)

  • Fixed an issue where the validator function was called twice when the Formulas plugin was enabled.
  • Introduced a new CSS style for cells of the checkbox type to restore previous behaviour. 

v9.0.0 (2021-06-01)

  • Breaking change New Formulas plugin, with an entirely different API. See the migration guide for a full list of changes. Removed the required hot-formula-parser dependency for the sake of an optional one, hyperformula.
  • Breaking change Changed the afterAutofill and beforeAutofill hooks' signatures. 
  • Upgraded eslint and eslint-related modules.
  • Added fit & fdescribe to restricted globals in test files.
  • Fixed bugs

v8.4.0 (2021-05-11)

  • Introduced a separated attribute for the label options (the label DOM element may wrap input or be placed next to it).
  • Introduced the modifyAutoColumnSizeSeed hook to let developers overwrite the default behaviour of the AutoColumnSize sampling.
  • Added support for hiding columns for the NestedHeaders plugin. 
  • Added ability to skip stacking actions by the UndoRedo plugin and introduced new hooks.
  • Bugfixed.

v8.3.2 (2021-03-16)

  • Lots of bugs fixed

v8.3.1 (2021-02-10)

  • Fixed an issue where the CSS files could be eliminated during tree-shaking

v8.3.0 (2021-01-28)

  • Introduced a new feature that allows postponing the table render and internal data cache update. The table rendering time can be reduced several-fold times by batching (using the batch method), multi-line API calls, or manually suspending rendering using the suspendRender and resumeRender methods.
  • Introduced a possibility to import: plugins, cell types, editors, renderers, validators.
  • Fixed a bug with auto-execution of the first item in the ContextMenu plugin.
  • Fixed a bug where column sorting with multi column sorting crashed the table.
  • Added a missing entry for the skipRowOnPaste option in the TypeScript definition file. 
  • Added missing tests to prevent from resurfacing.
  • Fixed an issue where altering columns did not update filters attached to columns.
  • Fixed typos and wrong return types in the TypeScript definition file.
  • Updated the dependencies causing potential security issues, as well as Babel configuration needed after the update.

v8.2.0 (2020-11-12)

  • Added a new type of an Index Map named LinkedPhysicalIndexToValueMap.
  • Added an external dependency, DOMPurify, to add HTML sanitization that should minimize the risk of inserting insecure code using Handsontable built-in functionalities.
  • Bugfixed

v8.1.0 (2020-10-01)

  • Added support for resizing non-contiguous selected rows and columns.
  • Improved performance for TrimRows, HiddenRows and HiddenColumns plugins for big datasets with many trimmed/hidden indexes.
  • Fixed bugs.

v8.0.0 (2020-08-05)

  • Added modifySourceData hook and setSourceDataAtCell method. 
  • Added new argument to scrollViewportTo method: optional considerHiddenIndexes which is a boolean.
  • Added additional information available in the cell meta object - the language. 
  • Added a possibility to allow cancelling of autofill in the beforeAutofill hook.
  • Added support for newer versions of moment, numbro and pikaday. 
  • Added afterAutoFill hook.
  • Added deprecated warning messages mechanism for plugin hooks.
  • Added missing types for instance.undoRedo. 
  • Added countRenderableColumns method to the TableView.
  • Added missing "hide" property in CustomBorders typings.
  • Added beforeSetCellMeta hook with an ability to cancel the changes.
  • Added additional test for autofill plugin.
  • Changed how manualRowMove and manualColumnMove plugins work
  • Click on a row header will select all cells (also hidden). 
  • Extracted Cell-Meta logic from Core to separate module. 
  • The CellMeta manager was refactored for future features and improvements.
  • Rows can be resized to less than rowHeights.
  • Left mouse button (LMB) click on the corner will now select all cells. 
  • The right mouse button (RMB) click on the corner, column and row headers will show just some options, defined by newly created specification 
  • Hidden indexes will no longer be rendered, as a consequence afterRenderer, modifyColWidth, beforeStretchingColumnWidth will be executable only on visible (meaning, rendered) rows and columns.
  • The getColWidth for hidden index will return 0 - it used to return 0.1
  • The modifyColWidth hook isn't called internally. However, it will be executed when the user will call the getColWidth.
  • Hidden rows/columns won't rendered anymore. As a consequence hooks beforeValueRender, beforeRenderer, afterRenderer, modifyColWidth, beforeStretchingColumnWidth etc. will be executed just for some of the columns (just the renderable ones). 
  • Selection behavior changed when hiding cells from the ContextMenu, now it is selecting a column on the right when there is space on right to the last selected column, selecting a column on the left otherwise. 
  • Developed a unified way to identify HOT "input" elements. All input elements owned by HOT got an attribute "data-hot-input" which are identified by that key. 
  • NestedHeaders plugin was rewritten, from now on, only a tree-like structure will be allowed, meaning, there will be no possibility to place nested headers in-between layers. 
  • CustomBorders plugin was adapted to work with HiddenColumns properly, from now on hiding cells at the start or at the end of a range will also hide their borders. Also, hiding a single cell with borders will hide all of its borders.
  • CollapsibleColumns will no longer use HiddenColumns plugin to work.
  • Modifying the table's data by reference and calling render() will not work properly anymore. From this point onward, all the data-related operations need to be performed using the API methods, such as populateFromArray or setDataAtCell. 
  • Removed dependencies between plugins: the manualColumnFreeze plugin doesn't use the manualColumnMove, the collapsibleColumns plugin doesn't use the hiddenColumns plugin, nestedRows plugin doesn't use the trimRows plugin, filters plugin doesn't use the trimRows plugin anymore. #5945 along with other adjustments
  • The minSpareRows and minRows options will ensure that the number of visible rows corresponds to the value provided to them (for example, the trimRows plugin won't have an impact on the number of displayed rows). 
  • toPhysicalRow and toVisualColumn now return null for non-existant rows/columns. 
  • The afterLoadData hook receives a different set of arguments. It used to be just the initialLoad flag, now the first argument is sourceData, followed by initialLoad. 
  • The manualColumnFreeze plugin unfreezes the column just after the "line of freeze".
  • The RecordTranslator object and the t property available in the plugins were removed.
  • After-prefixed hooks (afterLoadData, afterFilter, etc.) are now called just before the render call. 
  • Newly created rows and columns are now placed in the source data in the place calculated from its position in the visual context (they "stick" to their adjacent rows/columns). It also applies to moved rows and columns. 
  • When the nestedRows plugin is enabled, moving rows will be possible only using the UI or by calling the dragRows method of the manualRowMove plugin. 
  • The beforeRowResize, afterRowResize, beforeColumnResize, afterColumnResize hooks have the order of their arguments rearranged for the sake of consistency with other hooks.
  • Changed the argument structure in collapsibleColumns' toggleCollapsibleSection method.
  • Updated the moment, numbro and pikaday dependencies to their latest versions.
  • Standardize the z-index properties between the overlays.
  • Bugs fixed

v7.4.1 (2020-02-19)

  • Fixed an issue where the cell value could not be edited on mobile devices. 
  • Fixed an issue where white lines appeared at the bottom of cell headers.
  • Fixed a bug, where resizing the window (while using Angular) would result in Handsontable not stretching properly and throwing an error. 

v7.4.0 (2020-02-12)

  • Fixed the problem, where the onCellMouseUp hook was fired for all mouse buttons except the right one, which was not consistent with the onCellMouseDown hook.
  • To make the changes more consistent with the native dblclick event (which is triggered only for the left mouse button), the onCellDblClick and onCellCornerDblClick hooks were modified to also fire only for the left mouse button.
  • Updated moment, pikaday and numbro to their latest versions.
  • Fixed a bug with numbers not being presented properly with the pt_BR culture setting.
  • Extended the Babel config with the possibility to use private methods, optional chaining and nullish coalescing operator.

v7.3.0 (2019-10-23)

  • Add a new option to the Context Menu plugin - uiContainer. It allows declaring a DOM container, where all the Context Menu's element will be placed. It may come espacially handy when using Handsontable inside of an iframe or some other content-trimming context.
  • Bugs fixed.

v7.2.2 (2019-10-23)

  • Bugfix


  • Updated to the latest version
  • Cleanup the change log
  • Update readme


This awesome jQuery plugin is developed by handsontable. For more Advanced Usages, please check the demo page or visit the official website.