Nested Headers
Create hierarchical column headers with multiple levels to organize and structure your spreadsheet data presentation.
What's new with Version 13
- Editing:
splitNestedCell,mergeNestedCellandmoveNestedHeaderchange the structure programmatically. Every change is one undoable operation and travels to connected users- Interactive editing: rename, split and merge groups from the context menu, drag the boundary between two groups to move columns from one to the other, and select a group then drag it to move the group with all its columns. Disable it with
allowEditNestedHeaders: false- Selection: a click on a group selects its columns. Shift-click extends the selection over several groups, Ctrl-click adds a group, and a right-click on a selected group keeps the selection, so a context menu action applies to every selected group
- Events:
onchangenestednow fires after every change of the definitions, including cell updates, so a single handler can save the whole nested header configuration
Documentation
Methods
The following methods provide programmatic control over nested headers:
| Method | Description |
|---|---|
getNestedCell |
Get a nested header cell (DOM element).getNestedCell(x: number, y: number) => DOMElement |
setNestedCell |
Define the nested header cell attributes.setNestedCell(x: number, y: number, properties: Object) => void |
setNestedCell |
Define multiple nested header cell attributes.setNestedCell(updates: Object[]) => void |
getNestedHeaders |
Return the nested header definitions.getNestedHeaders() => Object[] |
setNestedHeaders |
Set the nested header definitions.setNestedHeaders(config: Object[][]) => void |
resetNestedHeaders |
Reset the nested header definitions.resetNestedHeaders() => void |
splitNestedCell |
Split a group at a grid column: the group keeps the columns before it, a new untitled group takes the rest.splitNestedCell(x: number, y: number) => boolean |
mergeNestedCell |
Merge the group owning a grid column with its right neighbour, or with every group up to the one owning the end column to; the combined group keeps the title. The context menu merges the whole selected range.mergeNestedCell(x: number, y: number, to?: number) => boolean |
moveNestedHeader |
Move a group to another position of its row, with all the columns it covers. x and destination are group indexes in the row.moveNestedHeader(x: number, y: number, destination: number) => boolean |
Every editing method is one undoable operation and travels to connected users. The x argument of splitNestedCell and mergeNestedCell is a grid column; the nested cell arguments of setNestedCell and moveNestedHeader are group indexes inside the nested row.
Interactive editing
Users can edit the nested headers directly:
- Context menu: right-click a group to rename it, split it at the clicked column, or merge it with the group to its right.
- Boundary drag: drag the right edge of a group to move columns from one group to its neighbour; both groups keep at least one column.
- Group drag: click a group to select its columns, then press the selected group and drag it. The drop snaps to the group boundaries of that row and the group moves with all its columns.
- Selection: Shift-click extends the selection over several groups, Ctrl-click adds a group as a second range, and a right-click on a group inside the selection keeps the selection.
Set allowEditNestedHeaders: false to disable the interactive editing; the programmatic methods stay available.
Initial Settings
Configure nested headers during spreadsheet initialization:
| Property | Description |
|---|---|
nestedHeaders?: Object[][] |
Worksheet nested header definitions. Possible attributes: { title: String, colspan: Number, tooltip: String, align: String, frozen: Boolean } |
allowEditNestedHeaders?: boolean |
Allow the user to rename, split, merge and drag the groups. The programmatic methods are not affected. Default: true |
Available Events
| Event | Description |
|---|---|
onchangenested |
Triggered after every change of the nested header definitions: a new definition, a reset, a cell update, a split, a merge or a move. The second argument is the complete definition, ready to be saved.onchangenested(worksheet: Object, config: Object[][]) => void |
onchangenestedcell |
Triggered when nested header cell properties are updated.onchangenestedcell(worksheet: Object, positionXOrArrayOfUpdates: number|Object[], positionY?: number, properties?: Object) => void |
Every change also reaches the persistence handler and, with the Jspreadsheet Server, is replayed on the other connected users.
Examples
Nested header example
This example demonstrates basic nested header configuration with programmatic updates. See a working example of a spreadsheet with nested headers on JSFiddle.
<html>
<script src="https://jspreadsheet.com/v13/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jsuites.net/v6/jsuites.css" type="text/css" />
<link rel="stylesheet" href="https://jspreadsheet.com/v13/jspreadsheet.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='Update' id="btn1"></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('ODE1MWFhYTRjNGQ4MzE1YzE0ZGJhYTNhNzYxZGRkNTkxMjAyNzdjYWEwZGRlYTBmODE0NmNhZGU0YWIxM2EzMDVkZTViYmVhMjY3MzA3MDc3NTEwNDU0ZjMxOGExMDBiNzMxMDNjNTE0NDU5MjVhOTA0ZDNhMjVmOWIzODI2NzgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprd01qRXlOek16TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
// Create the spreadsheet
let table = jspreadsheet(document.getElementById('spreadsheet'), {
worksheets: [{
data: [
['BR', 'Cheese', 1],
['CA', 'Apples', 0],
['US', 'Carrots', 1],
['GB', 'Oranges', 0],
],
columns: [
{
type: 'autocomplete',
title: 'Country',
width: '200px'
},
{
type: 'dropdown',
title: 'Food',
width: '100px',
source: ['Apples','Bananas','Carrots','Oranges','Cheese']
},
{
type: 'checkbox',
title: 'Stock',
width: '100px'
},
{
type: 'number',
title: 'Price',
width: '100px'
},
],
minDimensions: [6,4],
nestedHeaders:[
[
{
title: 'Supermarket information',
colspan: 6,
},
],
[
{
title: 'Location',
colspan: 1,
},
{
title: 'Other Information',
colspan: 2
},
{
title: 'Costs',
colspan: 3
}
],
]
}]
});
document.getElementById("btn1").onclick = () => table[0].setNestedCell(0, 0, { title:'New title',tooltip:'New tooltip' })
</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('ODE1MWFhYTRjNGQ4MzE1YzE0ZGJhYTNhNzYxZGRkNTkxMjAyNzdjYWEwZGRlYTBmODE0NmNhZGU0YWIxM2EzMDVkZTViYmVhMjY3MzA3MDc3NTEwNDU0ZjMxOGExMDBiNzMxMDNjNTE0NDU5MjVhOTA0ZDNhMjVmOWIzODI2NzgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprd01qRXlOek16TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
export default function App() {
// Spreadsheet array of worksheets
const spreadsheet = useRef();
// Data
const data = [
['BR', 'Cheese', 1],
['CA', 'Apples', 0],
['US', 'Carrots', 1],
['GB', 'Oranges', 0],
];
// Columns
const columns = [
{
type: 'autocomplete',
title: 'Country',
width: '200px'
},
{
type: 'dropdown',
title: 'Food',
width: '100px',
source: ['Apples', 'Bananas', 'Carrots', 'Oranges', 'Cheese']
},
{
type: 'checkbox',
title: 'Stock',
width: '100px'
},
{
type: 'number',
title: 'Price',
width: '100px'
},
];
// Nested headers
const nestedHeaders = [
[
{
title: 'Supermarket information',
colspan: 8,
},
],
[
{
title: 'Location',
colspan: 1,
},
{
title: 'Other Information',
colspan: 2
},
{
title: 'Costs',
colspan: 5
}
],
];
// Render component
return (
<>
<Spreadsheet ref={spreadsheet}>
<Worksheet data={data} columns={columns} nestedHeaders={nestedHeaders} minDimensions={[6, 4]}/>
</Spreadsheet>
<input type='button' value='Update'
onClick={() => spreadsheet.current[0].setNestedCell(0, 0, {title: 'New', tooltip: 'Tooltip'})}/>
</>
);
}
<template>
<Spreadsheet ref="spreadsheet">
<Worksheet :data="data" :columns="columns" :nestedHeaders="nestedHeaders" :minDimensions="[6,4]" />
</Spreadsheet>
<input type='button' value='Update' @click="update" />
</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('ODE1MWFhYTRjNGQ4MzE1YzE0ZGJhYTNhNzYxZGRkNTkxMjAyNzdjYWEwZGRlYTBmODE0NmNhZGU0YWIxM2EzMDVkZTViYmVhMjY3MzA3MDc3NTEwNDU0ZjMxOGExMDBiNzMxMDNjNTE0NDU5MjVhOTA0ZDNhMjVmOWIzODI2NzgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprd01qRXlOek16TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
export default {
components: {
Spreadsheet,
Worksheet,
},
data() {
// Data
const data = [
['BR', 'Cheese', 1],
['CA', 'Apples', 0],
['US', 'Carrots', 1],
['GB', 'Oranges', 0],
];
// Columns
const columns = [
{
type: 'autocomplete',
title: 'Country',
width: '200px'
},
{
type: 'dropdown',
title: 'Food',
width: '100px',
source: ['Apples','Bananas','Carrots','Oranges','Cheese']
},
{
type: 'checkbox',
title: 'Stock',
width: '100px'
},
{
type: 'number',
title: 'Price',
width: '100px'
},
];
// Nested headers
const nestedHeaders = [
[
{
title: 'Supermarket information',
colspan: 8,
},
],
[
{
title: 'Location',
colspan: 1,
},
{
title: 'Other Information',
colspan: 2
},
{
title: 'Costs',
colspan: 5
}
],
];
return {
data,
columns,
nestedHeaders,
};
},
methods: {
update() {
this.$refs.spreadsheet.current[0].setNestedCell(0, 0, { title:'New', tooltip:'Tooltip' })
}
}
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";
import "jspreadsheet/dist/jspreadsheet.css";
import "jsuites/dist/jsuites.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('ODE1MWFhYTRjNGQ4MzE1YzE0ZGJhYTNhNzYxZGRkNTkxMjAyNzdjYWEwZGRlYTBmODE0NmNhZGU0YWIxM2EzMDVkZTViYmVhMjY3MzA3MDc3NTEwNDU0ZjMxOGExMDBiNzMxMDNjNTE0NDU5MjVhOTA0ZDNhMjVmOWIzODI2NzgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprd01qRXlOek16TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
// Create component
@Component({
standalone: true,
selector: "app-root",
template: `
<div #spreadsheet></div>
<input type='button' value='Update' (click)="this.worksheets[0].setNestedCell(0, 0, { title:'New title',tooltip:'New tooltip' })">
`,
})
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: [
['BR', 'Cheese', 1],
['CA', 'Apples', 0],
['US', 'Carrots', 1],
['GB', 'Oranges', 0],
],
columns: [
{
type: 'autocomplete',
title: 'Country',
},
{
type: 'dropdown',
title: 'Food',
source: ['Apples','Bananas','Carrots','Oranges','Cheese']
},
{
type: 'checkbox',
title: 'Stock',
},
{
type: 'number',
title: 'Price',
},
],
minDimensions: [6,4],
nestedHeaders:[
[
{
title: 'Supermarket information',
colspan: 6,
},
],
[
{
title: 'Location',
colspan: 1,
},
{
title: 'Other Information',
colspan: 2
},
{
title: 'Costs',
colspan: 3
}
],
]
}]
});
}
}
Frozen nested headers
This example demonstrates frozen nested headers functionality with multi-level header structure.
<html>
<script src="https://jspreadsheet.com/v13/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jsuites.net/v6/jsuites.css" type="text/css" />
<link rel="stylesheet" href="https://jspreadsheet.com/v13/jspreadsheet.css" type="text/css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
<div id="spreadsheet"></div>
<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('ODE1MWFhYTRjNGQ4MzE1YzE0ZGJhYTNhNzYxZGRkNTkxMjAyNzdjYWEwZGRlYTBmODE0NmNhZGU0YWIxM2EzMDVkZTViYmVhMjY3MzA3MDc3NTEwNDU0ZjMxOGExMDBiNzMxMDNjNTE0NDU5MjVhOTA0ZDNhMjVmOWIzODI2NzgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprd01qRXlOek16TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
// Create the data grid
let table = jspreadsheet(document.getElementById('spreadsheet'), {
tabs: true,
toolbar: true,
tableOverflow: true,
tableWidth: 600,
worksheets: [{
minDimensions: [22,10],
freezeColumns: 2,
nestedHeaders:[
[
{
title: 'Location',
colspan: 2,
frozen: true,
},
{
title: 'Information',
colspan: 10
},
{
title: 'Another information',
colspan: 10
}
],
]
}]
});
</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('ODE1MWFhYTRjNGQ4MzE1YzE0ZGJhYTNhNzYxZGRkNTkxMjAyNzdjYWEwZGRlYTBmODE0NmNhZGU0YWIxM2EzMDVkZTViYmVhMjY3MzA3MDc3NTEwNDU0ZjMxOGExMDBiNzMxMDNjNTE0NDU5MjVhOTA0ZDNhMjVmOWIzODI2NzgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprd01qRXlOek16TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
export default function App() {
// Spreadsheet array of worksheets
const spreadsheet = useRef();
// Nested headers
const nestedHeaders = [
[
{
title: 'Location',
colspan: 2,
frozen: true,
},
{
title: 'Information',
colspan: 10
},
{
title: 'Another information',
colspan: 10
}
],
];
// Render component
return (
<Spreadsheet ref={spreadsheet} toolbar tabs tableOverflow tableWidth="600">
<Worksheet nestedHeaders={nestedHeaders} minDimensions={[22,10]} freezeColumns="2" />
</Spreadsheet>
);
}
<template>
<Spreadsheet ref="spreadsheet" toolbar tabs tableOverflow tableWidth="600">
<Worksheet :nestedHeaders="nestedHeaders" :minDimensions="[22,10]" freezeColumns="2" />
</Spreadsheet>
</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('ODE1MWFhYTRjNGQ4MzE1YzE0ZGJhYTNhNzYxZGRkNTkxMjAyNzdjYWEwZGRlYTBmODE0NmNhZGU0YWIxM2EzMDVkZTViYmVhMjY3MzA3MDc3NTEwNDU0ZjMxOGExMDBiNzMxMDNjNTE0NDU5MjVhOTA0ZDNhMjVmOWIzODI2NzgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprd01qRXlOek16TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
export default {
components: {
Spreadsheet,
Worksheet,
},
data() {
// Nested headers
const nestedHeaders = [
[
{
title: 'Location',
colspan: 2,
frozen: true,
},
{
title: 'Information',
colspan: 10
},
{
title: 'Another information',
colspan: 10
}
],
];
return {
nestedHeaders,
};
}
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";
// 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('ODE1MWFhYTRjNGQ4MzE1YzE0ZGJhYTNhNzYxZGRkNTkxMjAyNzdjYWEwZGRlYTBmODE0NmNhZGU0YWIxM2EzMDVkZTViYmVhMjY3MzA3MDc3NTEwNDU0ZjMxOGExMDBiNzMxMDNjNTE0NDU5MjVhOTA0ZDNhMjVmOWIzODI2NzgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprd01qRXlOek16TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
// Create component
@Component({
standalone: true,
selector: "app-root",
template: `<div #spreadsheet></div>`,
})
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, {
tabs: true,
toolbar: true,
tableOverflow: true,
tableWidth: 600,
worksheets: [{
minDimensions: [22,10],
freezeColumns: 2,
nestedHeaders:[
[
{
title: 'Location',
colspan: 2,
frozen: true,
},
{
title: 'Information',
colspan: 10
},
{
title: 'Another information',
colspan: 10
}
],
]
}]
});
}
}