Properties API

Cells, columns and rows carry definitions: the editor type, the mask, the alignment, a read-only flag, a width or a height. Version 13 exposes them through three explicit method pairs, one per target, with the same shape. Every setter takes an array of records, so batch operations are native, every change is one undoable operation, and only the records travel to connected users.

What's new with Version 13

  • Three explicit pairs: setCellProperties, setColumnProperties and setRowProperties, with their getters, replace the overloaded setProperty, getProperty, getOptions, setColumnOptions and getColumnOptions
  • Replace or update: a record replaces the definitions by default; update: true merges a subset over the current ones
  • Row definitions: rows gain the same programmatic API as columns
  • Events: onchangecellproperties, onchangecolumnproperties and onchangerowproperties replace onchangeproperty

Documentation

Methods

Method Description
getCellProperties The effective properties of a cell: its own properties, or the column definitions as fallback.
getCellProperties(x: Number, y: Number) => Object
setCellProperties Replace the own properties of one or more cells. null or an empty object resets a cell to the column definitions.
setCellProperties(records: { x: Number, y: Number, value: Object | null, update?: Boolean }[]) => void
setCellProperties The same operation with a map keyed by cell name.
setCellProperties(records: { [cellName: String]: Object | null }) => void
getColumnProperties The column definitions.
getColumnProperties(x: Number) => Object
setColumnProperties Replace the definitions of one or more columns. Position, elements and identity are preserved.
setColumnProperties(records: { column: Number, value: Object, update?: Boolean }[]) => void
getRowProperties The row definitions.
getRowProperties(y: Number) => Object
setRowProperties Replace the definitions of one or more rows. Position, element and identity are preserved.
setRowProperties(records: { row: Number, value: Object, update?: Boolean }[]) => void

Records

Attribute Description
x: number, y: number The zero-indexed coordinates, for cell records.
column: number The zero-indexed column, for column records.
row: number The zero-indexed row, for row records.
value: object | null The new definitions. For cells, null or {} resets the cell to its column definitions.
update?: boolean When true, only the given keys are applied over the current definitions, and only that delta travels to connected users. When false or omitted, the object replaces the definitions entirely.

Records with coordinates beyond the grid or invalid entries are skipped; the valid records of a batch still apply. A batch where nothing applies returns false.

Events

Event Description
onchangecellproperties After setCellProperties, with the records that were applied.
onchangecellproperties(worksheet: Object, records: Object[]) => void
onchangecolumnproperties After setColumnProperties, with the records that were applied.
onchangecolumnproperties(worksheet: Object, records: Object[]) => void
onchangerowproperties After setRowProperties, with the records that were applied.
onchangerowproperties(worksheet: Object, records: Object[]) => void

Replace or update

The setters use replace semantics by default: the object passed becomes the new definitions. To change a subset of properties, add update: true to the record.

// Replace: the cell becomes a dropdown and loses any other own property
worksheet.setCellProperties([
    { x: 0, y: 0, value: { type: 'dropdown', source: ['Yes', 'No'] } },
]);

// Update: only the mask changes, the type and the source stay
worksheet.setCellProperties([
    { x: 0, y: 0, value: { mask: '#.##0,00' }, update: true },
]);

// Reset: the cell follows the column definitions again
worksheet.setCellProperties([
    { x: 0, y: 0, value: null },
]);

Migration from version 12

Version 12 Version 13
setProperty(x, y, properties) setCellProperties([{ x, y, value: properties }])
setProperty(x, y, properties, true) setCellProperties([{ x, y, value: properties, update: true }])
setProperty(records) setCellProperties(records)
getProperty(x, y) / getOptions(x, y) getCellProperties(x, y)
setProperty(x, properties) setColumnProperties([{ column: x, value: properties }])
setColumnOptions(x, properties) setColumnProperties([{ column: x, value: properties }])
getProperty(x) / getColumnOptions(x) getColumnProperties(x)
onchangeproperty onchangecellproperties, onchangecolumnproperties

Examples

Cells, columns and rows

This example changes the definitions of a cell, a column and a row, and reads them back.

<html>
<script src="https://jspreadsheet.com/v13/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v13/jspreadsheet.css" type="text/css" />
<link rel="stylesheet" href="https://jsuites.net/v6/jsuites.css" type="text/css" />

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />

<div id="spreadsheet"></div>

<p>
    <input type="button" value="A1 as dropdown" id="btn1" />
    <input type="button" value="Column B as calendar" id="btn2" />
    <input type="button" value="Row 3 read-only" id="btn3" />
    <input type="button" value="Reset A1" id="btn4" />
</p>

<script>
// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('NjljZDM1NWRkMGMxYWU1N2ZiN2ExNjg3NzUyNWEzYzY0OGZmY2VmYTM0NjY4N2I0MzNjNTQ3MjQwMzkwNGRjNDNiZWFkNGNlODc4MTg0ZDE1NzZiMjA3ZDBkMDVlOWE3YmQ1ZWU5OGM0MDMxNzM4MTE2OTBhYTg2NDljMjIzMDUsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpnNE9ESTNOREkyTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9');

// Create the spreadsheet
let worksheets = jspreadsheet(document.getElementById('spreadsheet'), {
    worksheets: [{
        data: [
            ['Yes', '2026-01-10', 100],
            ['No', '2026-02-15', 250],
            ['Yes', '2026-03-20', 180],
        ],
        columns: [
            { title: 'Answer', width: 120 },
            { title: 'Date', width: 140 },
            { title: 'Amount', width: 100, type: 'number' },
        ],
        minDimensions: [3, 4],
    }],
    onchangecellproperties: function(worksheet, records) {
        console.log('cells', records);
    },
    onchangecolumnproperties: function(worksheet, records) {
        console.log('columns', records);
    },
    onchangerowproperties: function(worksheet, records) {
        console.log('rows', records);
    },
});

document.getElementById('btn1').onclick = function() {
    worksheets[0].setCellProperties([
        { x: 0, y: 0, value: { type: 'dropdown', source: ['Yes', 'No'] } },
    ]);
    console.log(worksheets[0].getCellProperties(0, 0));
}

document.getElementById('btn2').onclick = function() {
    worksheets[0].setColumnProperties([
        { column: 1, value: { type: 'calendar', format: 'DD/MM/YYYY' }, update: true },
    ]);
    console.log(worksheets[0].getColumnProperties(1));
}

document.getElementById('btn3').onclick = function() {
    worksheets[0].setRowProperties([
        { row: 2, value: { readOnly: true }, update: true },
    ]);
    console.log(worksheets[0].getRowProperties(2));
}

document.getElementById('btn4').onclick = function() {
    worksheets[0].setCellProperties([{ x: 0, y: 0, value: null }]);
}
</script>
</html>
import React, { useRef } from "react";
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/react";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";

// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('NjljZDM1NWRkMGMxYWU1N2ZiN2ExNjg3NzUyNWEzYzY0OGZmY2VmYTM0NjY4N2I0MzNjNTQ3MjQwMzkwNGRjNDNiZWFkNGNlODc4MTg0ZDE1NzZiMjA3ZDBkMDVlOWE3YmQ1ZWU5OGM0MDMxNzM4MTE2OTBhYTg2NDljMjIzMDUsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpnNE9ESTNOREkyTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9');

export default function App() {
    // Spreadsheet array of worksheets
    const spreadsheet = useRef();
    // Data
    const data = [
        ['Yes', '2026-01-10', 100],
        ['No', '2026-02-15', 250],
        ['Yes', '2026-03-20', 180],
    ];
    // Columns
    const columns = [
        { title: 'Answer', width: 120 },
        { title: 'Date', width: 140 },
        { title: 'Amount', width: 100, type: 'number' },
    ];

    const cell = () => spreadsheet.current[0].setCellProperties([
        { x: 0, y: 0, value: { type: 'dropdown', source: ['Yes', 'No'] } },
    ]);
    const column = () => spreadsheet.current[0].setColumnProperties([
        { column: 1, value: { type: 'calendar', format: 'DD/MM/YYYY' }, update: true },
    ]);
    const row = () => spreadsheet.current[0].setRowProperties([
        { row: 2, value: { readOnly: true }, update: true },
    ]);
    const reset = () => spreadsheet.current[0].setCellProperties([{ x: 0, y: 0, value: null }]);

    // Render component
    return (
        <>
            <Spreadsheet ref={spreadsheet} onchangecellproperties={(w, records) => console.log(records)}>
                <Worksheet data={data} columns={columns} minDimensions={[3, 4]} />
            </Spreadsheet>
            <input type="button" value="A1 as dropdown" onClick={cell} />
            <input type="button" value="Column B as calendar" onClick={column} />
            <input type="button" value="Row 3 read-only" onClick={row} />
            <input type="button" value="Reset A1" onClick={reset} />
        </>
    );
}
<template>
    <Spreadsheet ref="spreadsheet" :onchangecellproperties="log">
        <Worksheet :data="data" :columns="columns" :minDimensions="[3, 4]" />
    </Spreadsheet>
    <input type="button" value="A1 as dropdown" @click="cell" />
    <input type="button" value="Column B as calendar" @click="column" />
    <input type="button" value="Row 3 read-only" @click="row" />
    <input type="button" value="Reset A1" @click="reset" />
</template>

<script>
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/vue";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";

// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('NjljZDM1NWRkMGMxYWU1N2ZiN2ExNjg3NzUyNWEzYzY0OGZmY2VmYTM0NjY4N2I0MzNjNTQ3MjQwMzkwNGRjNDNiZWFkNGNlODc4MTg0ZDE1NzZiMjA3ZDBkMDVlOWE3YmQ1ZWU5OGM0MDMxNzM4MTE2OTBhYTg2NDljMjIzMDUsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpnNE9ESTNOREkyTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9');

export default {
    components: {
        Spreadsheet,
        Worksheet,
    },
    data() {
        return {
            data: [
                ['Yes', '2026-01-10', 100],
                ['No', '2026-02-15', 250],
                ['Yes', '2026-03-20', 180],
            ],
            columns: [
                { title: 'Answer', width: 120 },
                { title: 'Date', width: 140 },
                { title: 'Amount', width: 100, type: 'number' },
            ],
        };
    },
    methods: {
        log(worksheet, records) {
            console.log(records);
        },
        cell() {
            this.$refs.spreadsheet.current[0].setCellProperties([
                { x: 0, y: 0, value: { type: 'dropdown', source: ['Yes', 'No'] } },
            ]);
        },
        column() {
            this.$refs.spreadsheet.current[0].setColumnProperties([
                { column: 1, value: { type: 'calendar', format: 'DD/MM/YYYY' }, update: true },
            ]);
        },
        row() {
            this.$refs.spreadsheet.current[0].setRowProperties([
                { row: 2, value: { readOnly: true }, update: true },
            ]);
        },
        reset() {
            this.$refs.spreadsheet.current[0].setCellProperties([{ x: 0, y: 0, value: null }]);
        },
    }
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";

// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('NjljZDM1NWRkMGMxYWU1N2ZiN2ExNjg3NzUyNWEzYzY0OGZmY2VmYTM0NjY4N2I0MzNjNTQ3MjQwMzkwNGRjNDNiZWFkNGNlODc4MTg0ZDE1NzZiMjA3ZDBkMDVlOWE3YmQ1ZWU5OGM0MDMxNzM4MTE2OTBhYTg2NDljMjIzMDUsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpnNE9ESTNOREkyTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElpd2ljR2wyYjNRaVhTd2laR1Z0YnlJNmRISjFaWDA9');

// Create component
@Component({
    standalone: true,
    selector: "app-root",
    template: `
        <div #spreadsheet></div>
        <input type="button" value="A1 as dropdown" (click)="cell()" />
        <input type="button" value="Column B as calendar" (click)="column()" />
        <input type="button" value="Row 3 read-only" (click)="row()" />
        <input type="button" value="Reset A1" (click)="reset()" />
    `,
})
export class AppComponent {
    @ViewChild("spreadsheet") spreadsheet: ElementRef;
    // Worksheets
    worksheets: jspreadsheet.worksheetInstance[];
    // Create a new data grid
    ngAfterViewInit() {
        // Create spreadsheet
        this.worksheets = jspreadsheet(this.spreadsheet.nativeElement, {
            worksheets: [{
                data: [
                    ['Yes', '2026-01-10', 100],
                    ['No', '2026-02-15', 250],
                    ['Yes', '2026-03-20', 180],
                ],
                columns: [
                    { title: 'Answer', width: 120 },
                    { title: 'Date', width: 140 },
                    { title: 'Amount', width: 100, type: 'number' },
                ],
                minDimensions: [3, 4],
            }],
            onchangecellproperties: (worksheet, records) => console.log(records),
        });
    }
    cell() {
        this.worksheets[0].setCellProperties([
            { x: 0, y: 0, value: { type: 'dropdown', source: ['Yes', 'No'] } },
        ]);
    }
    column() {
        this.worksheets[0].setColumnProperties([
            { column: 1, value: { type: 'calendar', format: 'DD/MM/YYYY' }, update: true },
        ]);
    }
    row() {
        this.worksheets[0].setRowProperties([
            { row: 2, value: { readOnly: true }, update: true },
        ]);
    }
    reset() {
        this.worksheets[0].setCellProperties([{ x: 0, y: 0, value: null }]);
    }
}

See Also