Context Menu
Customize the Jspreadsheet context menus by defining a contextMenu
handler function. This handler receives default menu items, section information, coordinates, and event data, enabling the creation of dynamic, context-aware menu entries based on the clicked section and current application state.
What's new with Version 12
- New component with keyboard navigation support and better accessibility;
Documentation
Event Handler
contextMenu(worksheet, x, y, e, items, section, a1, a2) => Array | boolean
Parameter | Type | Description |
---|---|---|
worksheet |
Object | Instance of the active worksheet |
x |
Number | Column number |
y |
Number | Row number |
e |
Object | Mouse event handler |
items |
Array | Default context menu items |
section |
String | Click location: nested | header | row | cell | select-all | tabs | cloning | toolbar | footer |
a1 |
Any | First mixed argument that depends on the section |
a2 |
Any | Second mixed argument that depends on the section |
Returns: Array of menu item objects or boolean to cancel the action.
Menu Item Properties
The context menu handler should return an array of menu item objects. Each menu item can include the following properties:
Property | Description |
---|---|
type: string |
Menu item type: line | divisor | default |
title: string |
Menu item display title |
icon: string |
Material Design icon key for the menu item |
id: string |
HTML ID attribute for the DOM element |
disabled: boolean |
Whether the menu item is disabled |
onclick: function |
Click event handler for the menu item |
shortcut: string |
Keyboard shortcut description (typically displayed on the right) |
tooltip: string |
Tooltip text shown on hover |
submenu: Array of items |
Array of submenu items for nested menus |
Translation
Context menu text can be translated using jspreadsheet.setDictionary
to define translations for English terms.
jspreadsheet.setDictionary({
'Rename this worksheet': 'Renomear worksheet',
'Delete this worksheet': 'Apagar worksheet',
'Are you sure?': 'Tem certeza?',
'Rename this cell': 'Renomear essa celula',
'Cut': 'Cortar',
'Copy': 'Copiar',
'Paste': 'Colar',
'Insert a new column before': 'Inserir uma coluna antes',
'Insert a new column after': 'Inserir uma coluna depois',
'Delete selected columns': 'Apagar colunas selecionadas',
'Rename this column': 'Renomar essa coluna',
'Create a new row': 'Criar uma nova linha',
'Order ascending': 'Ordenar asc',
'Order descending': 'Ordenar desc',
'Insert a new row before': 'Inserir uma linha antes',
'Insert a new row after': 'Inserir uma nova linha depois',
'Delete selected rows': 'Apagar linhas selecionadas',
'Edit notes': 'Editar notas',
'Add notes': 'Adicionar notas',
'Notes': 'Notas',
'Clear notes': 'Apagar notas',
'Save as': 'Salvar como',
'About': 'Sobre',
});
Jspreadsheet v12 uses the LemonadeJS context menu component. For additional details and examples, visit: https://lemonadejs.com/docs/plugins/contextmenu.
Examples
Disable the context menu
To completely disable the context menu, define a contextMenu handler that returns false
.
<html>
<script src="https://jspreadsheet.com/v12/jspreadsheet.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v12/jspreadsheet.css" type="text/css" />
<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://fonts.googleapis.com/css?family=Material+Icons" />
<div id="spreadsheet"></div>
<script>
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YTRmYTJiNDQ0NDk5Mzc5MDUwNjc0ZDQ3NDAyYjZkY2NiYTFkZmFmZGI2NTk1ZDhiNTIwY2E0Njk0MTlmOTg5MzBiYWFmOGNlMWYwZDNjOGRjOGMzOTJhNGMwZWEyOGZjZDllODA0MWQxZTg0ZjE3N2UyY2ZlOTY5ZDkxOWYxNmEsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJOell5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// Create the spreadsheet
jspreadsheet(document.getElementById('spreadsheet'), {
worksheets: [{
minDimensions: [4,4],
}],
contextMenu: function() {
return false;
}
});
</script>
</html>
import React, {useRef} from "react";
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/react";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YTRmYTJiNDQ0NDk5Mzc5MDUwNjc0ZDQ3NDAyYjZkY2NiYTFkZmFmZGI2NTk1ZDhiNTIwY2E0Njk0MTlmOTg5MzBiYWFmOGNlMWYwZDNjOGRjOGMzOTJhNGMwZWEyOGZjZDllODA0MWQxZTg0ZjE3N2UyY2ZlOTY5ZDkxOWYxNmEsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJOell5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
export default function App() {
// Spreadsheet array of worksheets
const spreadsheet = useRef();
// Disable the context menu
const contextMenu = () => {
return false;
};
return (
<Spreadsheet ref={spreadsheet} contextMenu={contextMenu}>
<Worksheet minDimensions={[10, 10]}/>
</Spreadsheet>
);
}
<template>
<Spreadsheet ref="spreadsheet" :contextMenu="contextMenu">
<Worksheet :minDimensions="[4,4]" />
</Spreadsheet>
</template>
<script>
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/vue";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YTRmYTJiNDQ0NDk5Mzc5MDUwNjc0ZDQ3NDAyYjZkY2NiYTFkZmFmZGI2NTk1ZDhiNTIwY2E0Njk0MTlmOTg5MzBiYWFmOGNlMWYwZDNjOGRjOGMzOTJhNGMwZWEyOGZjZDllODA0MWQxZTg0ZjE3N2UyY2ZlOTY5ZDkxOWYxNmEsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJOell5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
export default {
components: {
Spreadsheet,
Worksheet,
},
data() {
// Disable the context menu
const contextMenu = () => {
return false;
};
return {
contextMenu
};
}
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";
import "jspreadsheet/dist/jspreadsheet.css"
import "jsuites/dist/jsuites.css"
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YTRmYTJiNDQ0NDk5Mzc5MDUwNjc0ZDQ3NDAyYjZkY2NiYTFkZmFmZGI2NTk1ZDhiNTIwY2E0Njk0MTlmOTg5MzBiYWFmOGNlMWYwZDNjOGRjOGMzOTJhNGMwZWEyOGZjZDllODA0MWQxZTg0ZjE3N2UyY2ZlOTY5ZDkxOWYxNmEsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJOell5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// 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, {
worksheets: [{
minDimensions: [4,4],
}],
// Disable the context menu
contextMenu: function() {
return false;
}
});
}
}
Customize the context menu
This example demonstrates how to customize context menu options based on the clicked section and application context.
<html>
<script src="https://jspreadsheet.com/v12/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v12/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>
<script>
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YTRmYTJiNDQ0NDk5Mzc5MDUwNjc0ZDQ3NDAyYjZkY2NiYTFkZmFmZGI2NTk1ZDhiNTIwY2E0Njk0MTlmOTg5MzBiYWFmOGNlMWYwZDNjOGRjOGMzOTJhNGMwZWEyOGZjZDllODA0MWQxZTg0ZjE3N2UyY2ZlOTY5ZDkxOWYxNmEsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJOell5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// Create a new spreadsheet
jspreadsheet(document.getElementById('spreadsheet'), {
worksheets: [{
data: [
["Apples", "Produce", 1.5, 10, "=C1*(1-(D1/100))"],
["Bread", "Bakery", 3.0, 20, "=C2*(1-(D2/100))"],
["Cheese", "Dairy", 5.0, 15, "=C3*(1-(D3/100))"],
["Eggs", "Dairy", 2.5, 0, "=C4*(1-(D4/100))"],
],
columns: [
{ title: 'Food', width: '140px' },
{ title: 'Category' },
{ title: 'Unit Price' },
{ title: 'Discount' },
{ title: 'Total ' },
],
allowComments: true,
}],
contextMenu: function(o, x, y, e, items, section) {
// Reset all items
let itemsArr = [];
// If the click was in the headers
if (section == 'header') {
// Items to the header only
itemsArr.push({
title: jSuites.translate('Execute one action'),
onclick: function() {
alert('test')
}
});
// Add a line
itemsArr.push({ type: 'line' });
}
// Save
itemsArr.push({
title: jSuites.translate('Save as'),
shortcut: 'Ctrl + S',
icon: 'save',
onclick: function () {
o.download();
}
});
// About
itemsArr.push({
title: jSuites.translate('About'),
onclick: function() {
alert('https://jspreadsheet.com');
}
});
return itemsArr;
}
});
</script>
</html>
import React, { useRef } from "react";
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/react";
import jSuites from "jsuites";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YTRmYTJiNDQ0NDk5Mzc5MDUwNjc0ZDQ3NDAyYjZkY2NiYTFkZmFmZGI2NTk1ZDhiNTIwY2E0Njk0MTlmOTg5MzBiYWFmOGNlMWYwZDNjOGRjOGMzOTJhNGMwZWEyOGZjZDllODA0MWQxZTg0ZjE3N2UyY2ZlOTY5ZDkxOWYxNmEsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJOell5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// Intercept the context menu
const contextMenu = (o, x, y, e, items, section) => {
// Reset all items
items = [];
// If the click was in the headers
if (section == 'header') {
// Items to the header only
items.push({
title: jSuites.translate('Execute one action'),
onclick: function() {
alert('test')
}
});
// Add a line
items.push({ type: 'line' });
}
// Save
items.push({
title: jSuites.translate('Save as'),
shortcut: 'Ctrl + S',
icon: 'save',
onclick: function () {
o.download();
}
});
// About
items.push({
title: jSuites.translate('About'),
onclick: function() {
alert('https://jspreadsheet.com');
}
});
return items;
}
export default function App() {
// Spreadsheet array of worksheets
const spreadsheet = useRef();
// Data
const data = [
["Apples", "Produce", 1.5, 10, "=C1*(1-(D1/100))"],
["Bread", "Bakery", 3.0, 20, "=C2*(1-(D2/100))"],
["Cheese", "Dairy", 5.0, 15, "=C3*(1-(D3/100))"],
["Eggs", "Dairy", 2.5, 0, "=C4*(1-(D4/100))"],
];
// Columns
const columns = [
{ title: 'Food', width: '140px' },
{ title: 'Category' },
{ title: 'Unit Price' },
{ title: 'Discount' },
{ title: 'Total ' },
];
return (
<Spreadsheet ref={spreadsheet} contextMenu={contextMenu}>
<Worksheet data={data} columns={columns} />
</Spreadsheet>
);
}
<template>
<Spreadsheet ref="spreadsheet" :contextMenu="contextMenu">
<Worksheet :data="data" :columns="columns" />
</Spreadsheet>
</template>
<script>
import { Spreadsheet, Worksheet, jspreadsheet } from "@jspreadsheet/vue";
import jSuites from "jsuites";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YTRmYTJiNDQ0NDk5Mzc5MDUwNjc0ZDQ3NDAyYjZkY2NiYTFkZmFmZGI2NTk1ZDhiNTIwY2E0Njk0MTlmOTg5MzBiYWFmOGNlMWYwZDNjOGRjOGMzOTJhNGMwZWEyOGZjZDllODA0MWQxZTg0ZjE3N2UyY2ZlOTY5ZDkxOWYxNmEsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJOell5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// Intercept the context menu
const contextMenu = (o, x, y, e, items, section) => {
// Reset all items
items = [];
// If the click was in the headers
if (section == 'header') {
// Items to the header only
items.push({
title: jSuites.translate('Execute one action'),
onclick: function() {
alert('test')
}
});
// Add a line
items.push({ type: 'line' });
}
// Save
items.push({
title: jSuites.translate('Save as'),
shortcut: 'Ctrl + S',
icon: 'save',
onclick: function () {
o.download();
}
});
// About
items.push({
title: jSuites.translate('About'),
onclick: function() {
alert('https://jspreadsheet.com');
}
});
return items;
}
export default {
components: {
Spreadsheet,
Worksheet,
},
data() {
// Data
const data = [
["Apples", "Produce", 1.5, 10, "=C1*(1-(D1/100))"],
["Bread", "Bakery", 3.0, 20, "=C2*(1-(D2/100))"],
["Cheese", "Dairy", 5.0, 15, "=C3*(1-(D3/100))"],
["Eggs", "Dairy", 2.5, 0, "=C4*(1-(D4/100))"],
];
// Columns
const columns = [
{ title: 'Food', width: '140px' },
{ title: 'Category' },
{ title: 'Unit Price' },
{ title: 'Discount' },
{ title: 'Total ' },
];
return {
contextMenu,
data,
columns
};
}
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YTRmYTJiNDQ0NDk5Mzc5MDUwNjc0ZDQ3NDAyYjZkY2NiYTFkZmFmZGI2NTk1ZDhiNTIwY2E0Njk0MTlmOTg5MzBiYWFmOGNlMWYwZDNjOGRjOGMzOTJhNGMwZWEyOGZjZDllODA0MWQxZTg0ZjE3N2UyY2ZlOTY5ZDkxOWYxNmEsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJOell5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
// 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, {
worksheets: [
{
data: [
['Apples', 'Produce', 1.5, 10, '=C1*(1-(D1/100))'],
['Bread', 'Bakery', 3.0, 20, '=C2*(1-(D2/100))'],
['Cheese', 'Dairy', 5.0, 15, '=C3*(1-(D3/100))'],
['Eggs', 'Dairy', 2.5, 0, '=C4*(1-(D4/100))'],
],
columns: [
{ title: 'Food', width: 140 },
{ title: 'Category' },
{ title: 'Unit Price' },
{ title: 'Discount' },
{ title: 'Total ' },
],
allowComments: true,
},
],
contextMenu: function (o, x, y, e, items, section) {
// Reset all items
items = [];
// If the click was in the headers
if (section == 'header') {
// Items to the header only
items.push({
title: 'Execute one action',
onclick: function () {
alert('test');
},
});
// Add a line
items.push({ type: 'line' });
}
// Save
items.push({
title: 'Save as',
shortcut: 'Ctrl + S',
icon: 'save',
onclick: function () {
o.download();
},
});
// About
items.push({
title: 'About',
onclick: function () {
alert('https://jspreadsheet.com');
},
});
return items;
},
});
}
}
Default context menu implementation
This is the reference implementation of the default context menu handler showing how different sections and conditions are handled.
/**
* Translation helper
*/
function T(t) {
return jSuites.translate(t);
}
/**
* Default context menu items
* @param {object} obj - worksheet
* @param {number} x
* @param {number} y
* @param {object} event
* @param {object} items
* @param {string} section
* @param {object\|number} argument1
* @param {number} argument2
* @return {array} Return the items to create the contextmenu
*/
function contextmenu(obj, x, y, e, items, section, a1, a2) {
// Reset all default items
items = [];
let o = obj.parent.config;
// Is mac
let ctrl = (navigator.userAgent.indexOf("Mac") !== -1) ? '⌘' : 'Ctrl';
// Click in the tabs
if (section === 'tabs') {
if (o.allowRenameWorksheet !== false) {
items.push({
title: T('Rename this worksheet'),
onclick: function() {
let newName = prompt(T('Rename this worksheet'), e.target.textContent);
if (newName) {
obj.parent.renameWorksheet(a1, newName);
}
}
});
}
if (o.allowDeleteWorksheet !== false) {
items.push({
title: T('Delete this worksheet'),
onclick: function() {
if (confirm(T('Are you sure?'), e.target.textContent)) {
obj.parent.deleteWorksheet(a1);
}
}
});
}
items.push({ type:'line' });
}
// Nested header only
if (section === 'nested') {
// Rename nested headers
items.push({
title: T('Rename this cell'),
onclick: function() {
// Get the new title
let text = prompt(T('Rename this cell'), e.target.textContent);
// Update the nested cell title
obj.setNestedCell(a1, a2, { title: text });
}
});
items.push({ type:'line' });
}
// Sections that affect the selection
if (section === 'header' || section === 'row' || section === 'cell' || section === 'nested') {
// Cut
items.push({
title: T('Cut'),
icon: 'content_cut',
shortcut: ctrl + ' + X',
onclick: function() {
obj.cut();
}
});
// Copy
items.push({
title: T('Copy'),
icon: 'content_copy',
shortcut: ctrl + ' + C',
onclick: function() {
obj.copy();
}
});
// Paste
if (navigator && navigator.clipboard && navigator.clipboard.readText) {
items.push({
title: T('Paste'),
icon: 'content_paste',
shortcut: ctrl + ' + V',
onclick: function() {
if (obj.selectedCell) {
navigator.clipboard.readText().then(function(text) {
if (text) {
let px = Math.min(obj.selectedCell[0], obj.selectedCell[2]);
let py = Math.min(obj.selectedCell[1], obj.selectedCell[3]);
obj.paste(px, py, text);
}
});
}
}
});
}
items.push({ type:'line' });
}
// Clicking in the headers
if (section === 'header') {
// Insert a new column
if (obj.options.allowInsertColumn !== false) {
items.push({
title: T('Insert a new column before'),
onclick: function() {
obj.insertColumn(1, parseInt(a1), 1);
}
});
items.push({
title: T('Insert a new column after'),
onclick: function() {
obj.insertColumn(1, parseInt(a1), 0);
}
});
}
// Delete a column
if (obj.options.allowDeleteColumn !== false) {
items.push({
title: T('Delete selected columns'),
onclick: function() {
obj.deleteColumn(obj.getSelectedColumns());
}
});
}
// Rename column
if (obj.options.allowRenameColumn !== false) {
items.push({
title: T('Rename this column'),
onclick: function() {
obj.setHeader(a1);
}
});
}
// Append new row
if (! obj.options.data.length) {
// Line
items.push({ type:'line' });
items.push({
title: T('Create a new row'),
onclick: function() {
obj.insertRow(0);
}
});
}
// Sorting
if (obj.options.columnSorting !== false) {
// Line
items.push({ type:'line' });
items.push({
title: T('Order ascending'),
onclick: function() {
obj.orderBy(a1, 0);
}
});
items.push({
title: T('Order descending'),
onclick: function() {
obj.orderBy(a1, 1);
}
});
items.push({ type:'line' });
}
items.push({
title: T('Hide'),
onclick: function() {
obj.hideColumn(obj.getSelectedColumns());
}
});
items.push({
title: T('Show'),
onclick: function() {
obj.showColumn(obj.getSelectedColumns());
}
});
items.push({ type:'line' });
}
// Row only
if (section === 'cell' || section === 'row') {
// Insert new row
if (obj.options.allowInsertRow !== false) {
items.push({
title: T('Insert a new row before'),
onclick: function() {
obj.insertRow(1, parseInt(y), 1);
}
});
items.push({
title: T('Insert a new row after'),
onclick: function() {
obj.insertRow(1, parseInt(y));
}
});
}
if (obj.options.allowDeleteRow !== false) {
items.push({
title: T('Delete selected rows'),
onclick: function() {
obj.deleteRow(obj.getSelectedRows(true));
}
});
}
items.push({ type:'line' });
}
if (section === 'row') {
items.push({
title: T('Hide'),
onclick: function() {
obj.hideRow(obj.getSelectedRows());
}
});
items.push({
title: T('Show'),
onclick: function() {
obj.showRow(obj.getSelectedRows());
}
});
items.push({ type:'line' });
}
// Click in the cell
if (section === 'cell') {
if (obj.options.allowComments !== false) {
let title = obj.records[a2][a1].element.getAttribute('title') || '';
items.push({
title: title ? T('Edit notes') : T('Add notes'),
icon: 'notes',
onclick: function() {
let comment = prompt(T('Notes'), title);
if (comment) {
let cell = jspreadsheet.helpers.getColumnNameFromCoords(a1, a2);
obj.setComments(cell, comment);
}
}
});
if (title) {
items.push({
title: T('Clear notes'),
onclick: function() {
let cell = jspreadsheet.helpers.getColumnNameFromCoords(a1, a2);
obj.setComments(cell, '');
}
});
}
// Line
items.push({ type:'line' });
}
}
if (section === 'select-all') {
items.push({
title: T('Show all'),
onclick: function() {
obj.showRow(obj.getSelectedRows());
obj.showColumn(obj.getSelectedColumns());
}
});
// Line
items.push({ type:'line' });
}
// Save
if (o.allowExport !== false) {
items.push({
title: T('Save as'),
icon: 'save',
shortcut: ctrl + ' + S',
onclick: function () {
obj.download();
}
});
}
// About
if (o.about !== false) {
items.push({
title: T('About'),
icon: 'info',
onclick: function() {
alert(jspreadsheet.version().print());
}
});
}
return items;
}
Plugin-based Customization
For complex applications, plugins offer a modular approach to context menu customization. This enables code reuse and better maintainability across multiple spreadsheet instances.
const myContextMenuPlugin = {
contextMenu: function(worksheet, x, y, e, items, section, a1, a2) {
// Custom menu logic here
return items;
}
};
// Apply plugin to spreadsheet
jspreadsheet(element, {
plugins: { myContextMenuPlugin },
// other options...
});