Read-only cells
Make specified cells read-only to protect them from unwanted changes but still allow navigation and copying of data.
Disable individual cells, entire columns, or entire rows to prevent user edits. Use readOnly on cells, columns, or the whole grid.
Overview
Disabling a cell makes the cell read-only or non-editable. Both have similar outcomes, with the following differences:
Read-only cellreadOnly: true | Non-editable celleditor: false |
|---|---|
Has an additional CSS class (htDimmed) | Has no additional CSS class |
| Copy works, paste doesn’t work | Copy-paste works |
| Drag-to-fill doesn’t work | Drag-to-fill works |
Can’t be changed by populateFromArray() | Can be changed by populateFromArray() |
Make the grid read-only
To make the entire grid read-only, set readOnly to true as a top-level grid option.
import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { return ( <HotTable data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} height="auto" colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" readOnly={true} /> );};
export default ExampleComponent;import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { return ( <HotTable data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} height="auto" colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" readOnly={true} /> );};
export default ExampleComponent;Make a column read-only
To make a column read-only, declare it in the columns configuration option. The column remains available for keyboard navigation and copying data (Ctrl/Cmd+C), but editing and pasting are disabled. The example below also defines a custom renderer that dims the read-only column, giving the user a visual cue that its cells are read-only.
import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';import { textRenderer } from 'handsontable/renderers/textRenderer';// register Handsontable's modulesregisterAllModules();const dimmedTextRenderer = (instance, td, ...rest) => { textRenderer(instance, td, ...rest); td.style.opacity = '0.6';};const ExampleComponent = () => { return (<HotTable data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} height="auto" colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" columns={[ { data: 'car', readOnly: true, renderer: dimmedTextRenderer, }, { data: 'year', }, { data: 'chassis', }, { data: 'bumper', }, ]}/>);};export default ExampleComponent;import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';import { BaseRenderer } from 'handsontable/renderers';import { textRenderer } from 'handsontable/renderers/textRenderer';
// register Handsontable's modulesregisterAllModules();
const dimmedTextRenderer: BaseRenderer = (instance, td, ...rest) => { textRenderer(instance, td, ...rest);
td.style.opacity = '0.6';};
const ExampleComponent = () => { return ( <HotTable data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} height="auto" colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" columns={[ { data: 'car', readOnly: true, renderer: dimmedTextRenderer, }, { data: 'year', }, { data: 'chassis', }, { data: 'bumper', }, ]} /> );};
export default ExampleComponent;Make a row read-only
To make an entire row read-only, use the cells function and set the readOnly property based on the row index, regardless of the column. The example below makes the second row (index 1) read-only.
import { useRef, useEffect } from 'react';import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';// register Handsontable's modulesregisterAllModules();const ExampleComponent = () => { const hotRef = useRef(null); useEffect(() => { const hot = hotRef.current?.hotInstance; hot?.updateSettings({ cells(row) { return row === 1 ? { readOnly: true } : {}; }, }); }); return (<HotTable ref={hotRef} data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} height="auto" autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation"/>);};export default ExampleComponent;import { useRef, useEffect } from 'react';import { HotTable, HotTableRef } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { const hotRef = useRef<HotTableRef>(null);
useEffect(() => { const hot = hotRef.current?.hotInstance;
hot?.updateSettings({ cells(row) { return row === 1 ? { readOnly: true } : {}; }, }); });
return ( <HotTable ref={hotRef} data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} height="auto" autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" /> );};
export default ExampleComponent;Make specific cells read-only
To make specific cells read-only, use the cells function to set the readOnly property conditionally. The example below makes cells that contain the word “Nissan” read-only.
import { useRef, useEffect } from 'react';import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { const hotRef = useRef(null);
useEffect(() => { const hot = hotRef.current?.hotInstance;
hot?.updateSettings({ cells(row, col) { const cellProperties = {};
if (hot.getData()[row][col] === 'Nissan') { cellProperties.readOnly = true; }
return cellProperties; }, }); });
return ( <HotTable ref={hotRef} data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} height="auto" autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" /> );};
export default ExampleComponent;import { useRef, useEffect } from 'react';import Handsontable from 'handsontable/base';import { HotTable, HotTableRef } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { const hotRef = useRef<HotTableRef>(null);
useEffect(() => { const hot = hotRef.current?.hotInstance;
hot?.updateSettings({ cells(row, col) { const cellProperties: Handsontable.CellMeta = {};
if (hot.getData()[row][col] === 'Nissan') { cellProperties.readOnly = true; }
return cellProperties; }, }); });
return ( <HotTable ref={hotRef} data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} height="auto" autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" /> );};
export default ExampleComponent;Non-editable cells behave like any other cells apart from preventing you from manually changing their values.
Make a column non-editable
To make a column non-editable, declare it in the columns configuration option. The column’s basic behavior does not change — you can still use keyboard navigation, Ctrl/Cmd+C, Ctrl/Cmd+V, and drag-to-fill. The example below also defines a custom renderer that dims the non-editable column, giving the user a visual cue that its cells are non-editable.
import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';import { textRenderer } from 'handsontable/renderers/textRenderer';// register Handsontable's modulesregisterAllModules();const dimmedTextRenderer = (instance, td, ...rest) => { textRenderer(instance, td, ...rest); td.style.opacity = '0.6';};const ExampleComponent = () => { return (<HotTable data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} height="auto" colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" columns={[ { data: 'car', editor: false, renderer: dimmedTextRenderer, }, { data: 'year', editor: 'numeric', }, { data: 'chassis', editor: 'text', }, { data: 'bumper', editor: 'text', }, ]}/>);};export default ExampleComponent;import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';import { BaseRenderer } from 'handsontable/renderers';import { textRenderer } from 'handsontable/renderers/textRenderer';
// register Handsontable's modulesregisterAllModules();
const dimmedTextRenderer: BaseRenderer = (instance, td, ...rest) => { textRenderer(instance, td, ...rest);
td.style.opacity = '0.6';};
const ExampleComponent = () => { return ( <HotTable data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} height="auto" colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" columns={[ { data: 'car', editor: false, renderer: dimmedTextRenderer, }, { data: 'year', editor: 'numeric', }, { data: 'chassis', editor: 'text', }, { data: 'bumper', editor: 'text', }, ]} /> );};
export default ExampleComponent;Make specific cells non-editable
To make specific cells non-editable, set editor: false in the cell configuration. The following example shows a table with non-editable cells containing the word “Nissan”.
import { useRef, useEffect } from 'react';import { HotTable } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { const hotRef = useRef(null);
useEffect(() => { const hot = hotRef.current?.hotInstance;
hot?.updateSettings({ cells(row, _col, prop) { const cellProperties = {};
if (hot.getDataAtRowProp(row, prop) === 'Nissan') { cellProperties.editor = false; } else { cellProperties.editor = 'text'; }
return cellProperties; }, }); });
return ( <HotTable ref={hotRef} data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} height="auto" autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" /> );};
export default ExampleComponent;import { useRef, useEffect } from 'react';import Handsontable from 'handsontable/base';import { HotTable, HotTableRef } from '@handsontable/react-wrapper';import { registerAllModules } from 'handsontable/registry';
// register Handsontable's modulesregisterAllModules();
const ExampleComponent = () => { const hotRef = useRef<HotTableRef>(null);
useEffect(() => { const hot = hotRef.current?.hotInstance;
hot?.updateSettings({ cells(row, _col, prop) { const cellProperties: Handsontable.CellMeta = {};
if (hot.getDataAtRowProp(row, prop as string) === 'Nissan') { cellProperties.editor = false; } else { cellProperties.editor = 'text'; }
return cellProperties; }, }); });
return ( <HotTable ref={hotRef} data={[ { car: 'Tesla', year: 2017, chassis: 'black', bumper: 'black' }, { car: 'Nissan', year: 2018, chassis: 'blue', bumper: 'blue' }, { car: 'Chrysler', year: 2019, chassis: 'yellow', bumper: 'black' }, { car: 'Volvo', year: 2020, chassis: 'white', bumper: 'gray' }, ]} colHeaders={['Car', 'Year', 'Chassis color', 'Bumper color']} height="auto" autoWrapRow={true} autoWrapCol={true} licenseKey="non-commercial-and-evaluation" /> );};
export default ExampleComponent;Accessibility
When ariaTags is enabled (the default), Handsontable adds aria-readonly="true" to the DOM element of every read-only cell, so screen readers announce that the cell can’t be edited. Non-editable cells (editor: false) don’t get this attribute, because Handsontable doesn’t treat them as read-only in the data model — only their editor is disabled.
For more accessibility features and testing guidance, see Accessibility.
Result
Read-only cells display with the htDimmed CSS class and block paste and drag-to-fill operations. Non-editable cells block manual editing but allow copy-paste and drag-to-fill.
Related API reference
Configuration options