Skip to main content

Applying editors to Grid cells

The Grid widget provides a predefined number of inline editors that can be applied to a column cell: text, combo, richselect, datepicker. Moreover, you can apply custom editors to column cells.

Applying in-built inline editors

To apply the inline editor to column cells, set the editor parameter of the columns property to the required value: "text" | "combo" | "datepicker" | "richselect". In this case all cells within a column will have the same editor type.

Example:

import { Grid } from "@svar-ui/react-grid";
import { getData } from "./common/data";

const { allData: data, countries, users } = getData();

const columns = [
{ id: "id", width: 50 },
{
id: "firstName",
header: 'Name - "text"',
editor: "text",
width: 180,
},
{
id: "country",
header: 'Country - "combo"',
editor: {
type: "combo",
config: { template: (option) => `${option.id}. ${option.name}` },
},
options: countries,
width: 180,
},
{
id: "date",
header: 'Date - "datepicker"',
width: 180,
editor: "datepicker",
template: (v) => (v ? v.toLocaleDateString() : ""),
},
{
id: "assigned",
header: 'Users - "richselect"',
width: 180,
editor: "richselect",
options: users,
},
];

export default function Example() {
return <Grid data={data} columns={columns} />;
}

Disabling editors

There are two common ways to disable the editor for specific cells:

Option 1. You can intercept the editor opening event and return false to prevent the editor from opening under certain conditions. For example, to disable editing of the "date" column for the row with id 1:

import { useRef, useEffect } from "react";
import { Grid } from "@svar-ui/react-grid";
import { getData } from "../data";

const { allData: data } = getData();

export default function Example() {
const apiRef = useRef(null);

useEffect(() => {
const api = apiRef.current;
if (!api) return;

// intercept open-editor events and block opening for date column in row id === 1
api.intercept("open-editor", (ev) => {
if (ev.column === "date" && ev.id === 1) {
return false; // block the editor
}
});

// NOTE: depending on the Grid API, you may need to remove the interceptor on unmount.
}, []);

const columns = [
{ id: "id", header: "ID", width: 60 },
{ id: "firstName", header: "First Name", editor: "text", width: 180 },
{
id: "date",
header: "Date",
editor: "datepicker",
width: 200,
},
];

return <Grid data={data} columns={columns} ref={apiRef} />;
}

Option 2. Alternatively, you can configure the editor property on a column as a function that receives the row and column info and returns the editor type or undefined/null to disable editing for that cell:

import { Grid } from "@svar-ui/react-grid";
import { getData } from "../data";

const { allData: data } = getData();

const columns = [
{ id: "id", header: "ID", width: 60 },
{ id: "firstName", header: "First Name", editor: "text", width: 180 },
{
id: "date",
header: "Date",
width: 200,
editor: (row, column) => {
// only enable editor for rows other than id === 1
if (row.id !== 1) {
return "datepicker";
}
// returning nothing disables editing for this cell
}
},
];

export default function Example() {
return (
<div style={{ padding: 20 }}>
<h4>The "Date" column is not editable in row with ID 1</h4>
<Grid data={data} columns={columns} />
</div>
);
}

Applying dynamic editors

If your data is heterogeneous and you want to assign different editors to cells within the same column based on the row data, you can specify the editor property as a function in the column configuration. This function returns the desired editor type or editor configuration depending on the row.

Example:

// mapping of column ids to their editors or editor configs
const editors = {
firstName: "text",
date: "datepicker",
country: {
type: "combo",
config: {
template: option => option.label,
options: countries,
},
},
};

const columns = [
{
id: "value",
editor: row => editors[row.id], // dynamically choose editor by row.id
template: (value, row) => {
if (row.id === "country") {
return countries.find(c => c.id === value)?.label || value;
}
return value instanceof Date ? value.toLocaleDateString() : value;
},
}
];

export default function Example() {
return <Grid data={data} columns={columns} />;
}

Make sure to pass the proper options to combo or richselect editors via their config. Define the template for the column to correctly display different data types depending on the editor used.

Customizing in-built editors

The Grid API allows applying a template and a custom React component to the cell editor (except the "text" type editor) via the config object of the editor parameter in the columns property.

Please note that for the "combo" editor the cell component will be applied to dropdown options only while for "datepicker" to the input field.

The example below shows how to apply a template to the "combo" editor in the Country column and the StatusStub component to the "richselect" editor in the Status column.

A template should be a function that takes an option and returns a string to be displayed (template?:(obj) => string). In our example each option should be of the format id.label (e.g., 1.USA). The cell property in the config object takes the custom component that should be applied to the editor. In our case, it's the StatusStub component.

import { Grid } from "@svar-ui/react-grid";
import { getData } from "../data";
import StatusStub from "../custom/StatusStub.jsx"; // import the component

const { allData: data, countries, users } = getData();

const statuses = [
{
id: 1,
label: "In progress",
type: "primary",
},
{
id: 2,
label: "Done",
type: "success",
},
{
id: 3,
label: "Not started",
type: "disabled",
},
];

const columns = [
{ id: "id", width: 50 },
{
id: "firstName",
header: 'Name - "text"',
editor: "text",
width: 180,
},
{
id: "country",
header: 'Country - "combo"',
editor: {
type: "combo",
config: { template: option => `${option.id}. ${option.label}` },
},
options: countries,
width: 180,
},
{
id: "date",
header: 'Date - "datepicker"',
width: 180,
editor: "datepicker",
template: v => (v ? v.toLocaleDateString() : ""),
},
{
id: "user",
header: 'User - "richselect"',
width: 180,
editor: "richselect",
options: users,
},
{
id: "status",
resize: true,
header: "Status",
width: 133,
editor: {
type: "richselect",
config: { cell: StatusStub },
},
options: statuses,
},
];

export default function Example() {
return <Grid data={data} columns={columns} />;
}

StatusStub component (converted to React):

export default function StatusStub({ data }) {
return (
<div className={`status ${data.type}`}>
<div className="status-wrapper">
<div className="dot" />
<span className="name">{data.label}</span>
</div>
</div>
);
}

Example CSS for StatusStub (move to .css/.module.css as needed):

.status {
height: 100%;
width: 100%;
display: flex;
align-items: center;
}
.status .status-wrapper {
border-radius: 18px;
padding: 2px 8px;
display: flex;
gap: 4px;
align-items: center;
justify-content: center;
position: relative;
}
.status .status-wrapper::before {
position: absolute;
height: 100%;
width: 100%;
content: "";
border-radius: 18px;
opacity: 0.15;
}
.status .dot {
height: 6px;
width: 6px;
border-radius: 50%;
}

Applying custom editors

Grid allows adding custom components to column cells. The rules of embedding custom components are described here: Adding custom content to cells

The example below shows how to customize the Checkbox component and call the update-cell action via the api.exec() method so that the cell is updated directly in Grid.

CheckboxCell (React) - get access to Grid api via component props:

import { Checkbox } from "@svar-ui/react-core"; // import the Checkbox component

export default function CheckboxCell({ row, column, api }) {
function onChange(ev) {
// `ev` is expected to contain `{ value }` as the editor event payload.
const { value } = ev;
api.exec("update-cell", {
id: row.id,
column: column.id,
value,
});
}

return <Checkbox value={row[column.id]} onChange={onChange} />;
}

In the next example we import the component and apply it to the Grid cell:

import CheckboxCell from "../custom/CheckboxCell.jsx";
import { Grid } from "@svar-ui/react-grid";

import { getData } from "./common/data";
const { data } = getData();

const columns = [
{ id: "id", width: 50 },
{ id: "checked", cell: CheckboxCell, width: 36 },
];

export default function Example() {
return <Grid data={data} columns={columns} />;
}

Related articles: