demo D93
Conditional Editing: Read-Only Columns and Cells in React
Columns that never edit, and cells that depend on the record
edit.enabled: (row) => …
This grid locks some columns entirely and makes others read-only per row, so a status cell stops editing once an order ships. It expresses which cells a user may change as a rule on the record, not a manual check scattered through the app.
This is the React version. The grid mounts through the createLatticeGrid adapter, which takes its configuration as ordinary props and hands back the live grid through a ref. The grid below is the same one every other tab runs.
The configuration
<link rel="stylesheet" href="https://cdn.latticegrid.dev/lattice-grid@1.107.0/lattice-grid.min.css">
<div id="grid"></div>
<script type="module">
import React from 'https://esm.sh/react@18';
import { createRoot } from 'https://esm.sh/react-dom@18/client';
import { createGrid } from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/lattice-grid.esm.min.js';
import createLatticeGrid from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/modules/react.esm.min.js';
const LatticeGrid = createLatticeGrid({ React, createGrid });
// Three different answers to "can this be edited": never, always, and it
// depends on the record. The predicate is asked per cell, so two rows in the
// same column can disagree.
const columns = [
// No edit block at all, so these columns are never editable. That is the
// default rather than something to switch off.
{ field: 'id', title: 'Order', layout: { width: 120, pin: 'start' } },
{ field: 'reference', title: 'Reference', layout: { width: 130 } },
{ field: 'stage', title: 'Stage', filter: { type: 'set' }, edit: true },
{
field: 'budget', title: 'Budget', type: 'number', layout: { width: 140 },
format: { style: 'currency', currency: 'GBP' }, total: 'sum',
edit: { enabled: ({ data }) => data?.stage !== 'done' },
},
{
field: 'circuits', title: 'Circuits', type: 'number', layout: { width: 110 },
edit: { enabled: ({ data }) => data?.stage !== 'done' && data?.signedOff !== true },
},
];
const rows = [/* work orders, each with a stage and a signedOff flag */];
function App() {
return (
<LatticeGrid
rowKey="id"
selection="multiple"
edit
columns={columns}
rows={rows}
style={{ height: '540px' }}
/>
);
}
createRoot(document.getElementById('grid')).render(<App />);
</script>
Locking a column, or a single cell, without a second grid
Some columns should never open an editor, and some cells should only be locked depending on the row they sit in: a total column that is always computed, or a status column that stops being editable once an order is shipped. Lattice Grid handles both with one option, edit.enabled: (row) => …, set either as a plain boolean for a column-wide rule or as a function for a per-cell one. When the function returns false for a row, that cell never opens an editor on double-click or keystroke and is skipped by Tab-to-edit navigation, so a mixed grid of editable and locked cells needs no second read-only grid layered on top and no disabled overlay drawn over individual cells. The function receives the row already resolved for that cell, so a rule such as “locked once status is closed” costs one property check per cell rather than a pass over the dataset. Because the read-only state is expressed at the data layer rather than the render layer, a screen reader encounters the cell with the correct read-only role from the first render, not after an editor briefly mounts and is torn down. This is the mechanism a JavaScript data grid needs to mix computed, permission-gated, and freely editable cells in one table without maintaining a second component for the parts that cannot change.
How do I make specific cells read-only in a data grid?
Set edit.enabled on the column to a function of the row, returning false for any row where that cell should not be editable, or a plain false to lock the whole column. Locked cells skip the editor on double-click and keystroke, are excluded from Tab-to-edit focus order, and are read to assistive technology as non-editable from the first render, with no separate overlay or second grid required.