Documentation
Cell Editing
Simple Table provides powerful cell editing capabilities, allowing users to modify data directly within the table interface. This creates a more interactive and efficient user experience for data entry and management. Unlike competitors, Simple Table provides specialized editors for different data types including strings, numbers, dates, booleans, and enumerated values.
React TSX
Copy
1import { useState } from "react";2import {SimpleTable} from "@simple-table/react";import type { Theme, CellChangeProps } from "@simple-table/react";3import { cellEditingConfig } from "./cell-editing.demo-data";4import "@simple-table/react/styles.css";56const CellEditingDemo = ({7 height = "400px",8 theme,9}: {10 height?: string | number;11 theme?: Theme;12}) => {13 const [data, setData] = useState([...cellEditingConfig.rows]);1415 const handleCellEdit = ({ accessor, newValue, row }: CellChangeProps) => {16 setData((prev) =>17 prev.map((item) =>18 item.id === row.id ? { ...item, [accessor]: newValue } : item19 )20 );21 };2223 return (24 <SimpleTable25 defaultHeaders={cellEditingConfig.headers}26 rows={data}27 height={height}28 theme={theme}29 onCellEdit={handleCellEdit}30 />31 );32};3334export default CellEditingDemo;
Vue SFC
Copy
1<template>2 <SimpleTable3 :default-headers="cellEditingConfig.headers"4 :rows="data"5 :height="height"6 :theme="theme"7 @cell-edit="handleCellEdit"8 />9</template>1011<script setup lang="ts">12import { ref } from "vue";13import {SimpleTable} from "@simple-table/vue";import type { Theme, CellChangeProps } from "@simple-table/vue";14import { cellEditingConfig } from "./cell-editing.demo-data";15import "@simple-table/vue/styles.css";1617withDefaults(defineProps<{ height?: string | number; theme?: Theme }>(), {18 height: "400px",19});2021const data = ref([...cellEditingConfig.rows]);2223const handleCellEdit = ({ accessor, newValue, row }: CellChangeProps) => {24 data.value = data.value.map((item) =>25 item.id === row.id ? { ...item, [accessor]: newValue } : item26 );27};28</script>
Angularcell-editing-demo.component.ts
Copy
1import { Component, Input } from "@angular/core";2import {SimpleTableComponent} from "@simple-table/angular";import type { AngularHeaderObject, CellChangeProps, Theme } from "@simple-table/angular";3import { cellEditingConfig } from "./cell-editing.demo-data";4import "@simple-table/angular/styles.css";56@Component({7 selector: "cell-editing-demo",8 standalone: true,9 imports: [SimpleTableComponent],10 template: `11 <simple-table12 [rows]="data"13 [defaultHeaders]="headers"14 [height]="height"15 [theme]="theme"16 (cellEdit)="onCellEdit($event)"17 ></simple-table>18 `,19})20export class CellEditingDemoComponent {21 @Input() height: string | number = "400px";22 @Input() theme?: Theme;2324 readonly headers: AngularHeaderObject[] = cellEditingConfig.headers;25 data = [...cellEditingConfig.rows];2627 onCellEdit({ accessor, newValue, row }: CellChangeProps): void {28 this.data = this.data.map((item) =>29 item.id === row.id ? { ...item, [accessor]: newValue } : item30 );31 }32}333435// cell-editing.demo-data.ts36// Self-contained demo table setup for this example.37import type { AngularHeaderObject } from "@simple-table/angular";383940export const cellEditingHeaders: AngularHeaderObject[] = [41 { accessor: "firstName", label: "First Name", width: "1fr", minWidth: 100, isEditable: true, type: "string" },42 { accessor: "lastName", label: "Last Name", width: 120, isEditable: true, type: "string" },43 { accessor: "role", label: "Role", width: 120, isEditable: true, type: "enum", enumOptions: [44 { label: "Developer", value: "Developer" },45 { label: "Designer", value: "Designer" },46 { label: "Manager", value: "Manager" },47 { label: "Marketing", value: "Marketing" },48 { label: "QA", value: "QA" },49 ]},50 { accessor: "hireDate", label: "Hire Date", width: 120, isEditable: true, type: "date" },51 { accessor: "isActive", label: "Active", width: 100, isEditable: true, type: "boolean" },52 { accessor: "salary", label: "Salary", width: 120, isEditable: true, type: "number" },53];5455export const cellEditingData = [56 { id: 1, firstName: "Ranger", lastName: "Wilde", role: "Manager", hireDate: "2019-03-12", isActive: true, salary: 89000 },57 { id: 2, firstName: "Safari", lastName: "Brooks", role: "Designer", hireDate: "2021-07-18", isActive: true, salary: 74000 },58 { id: 3, firstName: "Forest", lastName: "Rivers", role: "Manager", hireDate: "2018-11-08", isActive: true, salary: 94000 },59 { id: 4, firstName: "Savanna", lastName: "Fields", role: "Developer", hireDate: "2022-02-14", isActive: false, salary: 81000 },60 { id: 5, firstName: "Canyon", lastName: "Stone", role: "Marketing", hireDate: "2021-09-20", isActive: true, salary: 73000 },61 { id: 6, firstName: "Meadow", lastName: "Vale", role: "QA", hireDate: "2020-06-25", isActive: true, salary: 79000 },62 { id: 7, firstName: "Ridge", lastName: "Peak", role: "Manager", hireDate: "2019-01-20", isActive: true, salary: 92000 },63 { id: 8, firstName: "Tundra", lastName: "Frost", role: "Developer", hireDate: "2022-05-03", isActive: false, salary: 85000 },64 { id: 9, firstName: "Prairie", lastName: "Wind", role: "Designer", hireDate: "2021-10-12", isActive: true, salary: 77000 },65 { id: 10, firstName: "Delta", lastName: "Flow", role: "Developer", hireDate: "2020-08-17", isActive: true, salary: 83000 },66 { id: 11, firstName: "Grove", lastName: "Shade", role: "Designer", hireDate: "2022-01-09", isActive: true, salary: 76000 },67 { id: 12, firstName: "Cliff", lastName: "Edge", role: "QA", hireDate: "2019-12-04", isActive: false, salary: 82000 },68];6970export const cellEditingConfig = {71 headers: cellEditingHeaders,72 rows: cellEditingData,73} as const;74
Svelte
Copy
1<script lang="ts">2 import {SimpleTable} from "@simple-table/svelte"; import type { Theme, CellChangeProps } from "@simple-table/svelte";3 import { cellEditingConfig } from "./cell-editing.demo-data";4 import "@simple-table/svelte/styles.css";56 let { height = "400px", theme }: { height?: string | number; theme?: Theme } = $props();7 let data = $state([...cellEditingConfig.rows]);89 function handleCellEdit({ accessor, newValue, row }: CellChangeProps) {10 data = data.map((item) =>11 item.id === row.id ? { ...item, [accessor]: newValue } : item12 );13 }14</script>1516<SimpleTable17 defaultHeaders={cellEditingConfig.headers}18 rows={data}19 {height}20 {theme}21 onCellEdit={handleCellEdit}22/>
Solid TSX
Copy
1import { createSignal } from "solid-js";2import {SimpleTable} from "@simple-table/solid";import type { Theme, CellChangeProps } from "@simple-table/solid";3import { cellEditingConfig } from "./cell-editing.demo-data";4import "@simple-table/solid/styles.css";56export default function CellEditingDemo(props: { height?: string | number; theme?: Theme }) {7 const [data, setData] = createSignal([...cellEditingConfig.rows]);89 const handleCellEdit = ({ accessor, newValue, row }: CellChangeProps) => {10 setData((prev) =>11 prev.map((item) => (item.id === row.id ? { ...item, [accessor]: newValue } : item))12 );13 };1415 return (16 <SimpleTable17 defaultHeaders={cellEditingConfig.headers}18 rows={data()}19 height={props.height ?? "400px"}20 theme={props.theme}21 onCellEdit={handleCellEdit}22 />23 );24}
TypeScriptCellEditingDemo.ts
Copy
1import { SimpleTableVanilla } from "simple-table-core";2import type { Theme, CellChangeProps } from "simple-table-core";3import { cellEditingConfig } from "./cell-editing.demo-data";4import "simple-table-core/styles.css";56export function renderCellEditingDemo(7 container: HTMLElement,8 options?: { height?: string | number; theme?: Theme }9): SimpleTableVanilla {10 let rows = [...cellEditingConfig.rows];1112 const table = new SimpleTableVanilla(container, {13 defaultHeaders: cellEditingConfig.headers,14 rows,15 height: options?.height ?? "400px",16 theme: options?.theme,17 onCellEdit: ({ accessor, newValue, row }: CellChangeProps) => {18 rows = rows.map((item) =>19 item.id === row.id ? { ...item, [accessor]: newValue } : item20 );21 table.update({ rows });22 },23 });24 return table;25}262728// cell-editing.demo-data.ts29// Self-contained demo table setup for this example.30import type { HeaderObject } from "simple-table-core";313233export const cellEditingHeaders: HeaderObject[] = [34 { accessor: "firstName", label: "First Name", width: "1fr", minWidth: 100, isEditable: true, type: "string" },35 { accessor: "lastName", label: "Last Name", width: 120, isEditable: true, type: "string" },36 { accessor: "role", label: "Role", width: 120, isEditable: true, type: "enum", enumOptions: [37 { label: "Developer", value: "Developer" },38 { label: "Designer", value: "Designer" },39 { label: "Manager", value: "Manager" },40 { label: "Marketing", value: "Marketing" },41 { label: "QA", value: "QA" },42 ]},43 { accessor: "hireDate", label: "Hire Date", width: 120, isEditable: true, type: "date" },44 { accessor: "isActive", label: "Active", width: 100, isEditable: true, type: "boolean" },45 { accessor: "salary", label: "Salary", width: 120, isEditable: true, type: "number" },46];4748export const cellEditingData = [49 { id: 1, firstName: "Ranger", lastName: "Wilde", role: "Manager", hireDate: "2019-03-12", isActive: true, salary: 89000 },50 { id: 2, firstName: "Safari", lastName: "Brooks", role: "Designer", hireDate: "2021-07-18", isActive: true, salary: 74000 },51 { id: 3, firstName: "Forest", lastName: "Rivers", role: "Manager", hireDate: "2018-11-08", isActive: true, salary: 94000 },52 { id: 4, firstName: "Savanna", lastName: "Fields", role: "Developer", hireDate: "2022-02-14", isActive: false, salary: 81000 },53 { id: 5, firstName: "Canyon", lastName: "Stone", role: "Marketing", hireDate: "2021-09-20", isActive: true, salary: 73000 },54 { id: 6, firstName: "Meadow", lastName: "Vale", role: "QA", hireDate: "2020-06-25", isActive: true, salary: 79000 },55 { id: 7, firstName: "Ridge", lastName: "Peak", role: "Manager", hireDate: "2019-01-20", isActive: true, salary: 92000 },56 { id: 8, firstName: "Tundra", lastName: "Frost", role: "Developer", hireDate: "2022-05-03", isActive: false, salary: 85000 },57 { id: 9, firstName: "Prairie", lastName: "Wind", role: "Designer", hireDate: "2021-10-12", isActive: true, salary: 77000 },58 { id: 10, firstName: "Delta", lastName: "Flow", role: "Developer", hireDate: "2020-08-17", isActive: true, salary: 83000 },59 { id: 11, firstName: "Grove", lastName: "Shade", role: "Designer", hireDate: "2022-01-09", isActive: true, salary: 76000 },60 { id: 12, firstName: "Cliff", lastName: "Edge", role: "QA", hireDate: "2019-12-04", isActive: false, salary: 82000 },61];6263export const cellEditingConfig = {64 headers: cellEditingHeaders,65 rows: cellEditingData,66} as const;67
Basic Editing Setup
To enable cell editing in Simple Table, you need to:
- Add the
isEditable: trueproperty to the columns you want to make editable - Provide an
onCellEdithandler to manage the data updates
Cell Editing Properties
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
HeaderObject.isEditableboolean | Optional | Makes a column editable, allowing users to modify cell values directly within the table interface. | |
HeaderObject.type | Optional | Specifies the data type and editor for the column. Simple Table provides specialized editors for different data types. Options: string number boolean date enum | |
onCellEdit | Optional | Callback function that is triggered when a cell value is edited. Receives the cell change properties including accessor, newValue, and row data. |
Copy-Paste Functionality
Simple Table includes built-in copy-paste functionality that works seamlessly with cell editing:
- Users can copy data from any selected cells using keyboard shortcuts (Ctrl+C/⌘+C)
- Data can be pasted from external sources like spreadsheets or other applications
- Important: Pasting is only allowed into columns that have
isEditable: true - Non-editable columns will be skipped during paste operations
Copy-Paste Restrictions
When pasting data, only columns marked with isEditable: true will accept the pasted values. This ensures data integrity and prevents accidental modification of read-only columns like IDs or calculated fields.