Skip to main content

Adding and configuring the context menu

You can add/configure the context menu in one of the two ways:

  • add the default menu and/or modify necessary settings by importing the ContextMenu component from wx-svelte-grid
  • add a custom menu by importing the ContextMenu component from wx-svelte-menu; for a custom menu you can also apply the ActionMenu

Adding the default context menu

To add a context menu with default menu options, import the ContextMenu component from "wx-svelte-grid" and wrap Grid into the ContextMenu tag. You should also pass the api object to the ContextMenu component.

Example:

<script>
import { Grid, ContextMenu } from "wx-svelte-grid";
import { getData } from "./common/data";

let table = $state();

</script>

<ContextMenu api={table}>
<Grid {data} {columns} bind:this={table} />
</ContextMenu>

Customizing the context menu

To customize menu options, import the ContextMenu component, and then modify the required settings. The example below shows how to add the separator after the "Add after" option, and display the menu at the bottom of the selected item.

<script>
import { getData } from "../data";
import { Grid, ContextMenu } from "wx-svelte-grid";

let table = $state();

const data = getData();

const options = [
{
id: "add:before",
text: "Add before",
icon: "wxi-table-row-plus-before",
},
{
id: "add:after",
text: "Add after",
icon: "wxi-table-row-plus-after",
},
{ type: "separator" },
{ id: "copy", text: "Copy", icon: "wxi-content-copy" },
{ type: "separator" },
{ id: "delete", text: "Delete", icon: "wxi-delete-outline" },
];
</script>

<ContextMenu api={table} {options} at={"bottom"}>
<Grid {data} {columns} bind:this={table} />
</ContextMenu>

Adding a custom context menu

In the example below we add a custom menu with two menu options: "Add" with subitems and "Delete". To add a custom menu, in the example below we do the following:

  • import the ContextMenu component from wx-svelte-menu
  • add the options array
  • add the function to handle clicks on the menu items
  • pass the the bind:this construct to the Grid tag
<script>
import { getData } from "./common/data";
import { Grid } from "wx-svelte-grid";
import { ContextMenu } from "wx-svelte-menu"; // import the component
const { data, columns } = getData();

let table = $state();

// add menu options
const options = [
{
id: "add",
text: "Add",
icon: "wxi-table-row-plus",
// add subitems
data: [
{ id: "add-before:child", icon: "wxi-table-row-plus-before", text: "Add before this row" },
{ id: "add-after:child", icon: "wxi-table-row-plus-after", text: "Add after this row" },
],
},
{ type: "separator" },
{ id: "delete", text: "Delete", icon: "wxi-delete-outline" },
];

const handleClicks = ev => {
const option = ev.action;
if (option) {
const id = table.getState().selected;
switch (option.id) {
case "add-before:child":
table.exec("add-row", { row: {}, before: id });
break;
case "add-after:child":
table.exec("add-row", { row: {}, after: id });
break;
case "delete":
table.exec("delete-row", { id });
break;
default:
helpers.showNotice({ text: `You clicked ${option.text}` });
}
}
};

// select item and open menu for it
function getItem(id) {
if (id) table.exec("select-row", { id });
return id;
}
</script>

<ContextMenu
api={table}
{options}
onclick={handleClicks}
at="point"
resolver={getItem}>
<Grid {data} {columns} bind:this={table} />
</ContextMenu>

Adding a header menu

The header context menu allows hiding/showing the columns by clicking their names in this menu.

To add the default context menu for all column headers, you need to import the HeaderMenu component to the page (from the wx-svelte-grid package), wrap the Grid tag inside the HeaderMenu tag and pass the api object to the HeaderMenu component.

Example:

<script>
import { getData } from "./common/data";
import { Grid, HeaderMenu } from "wx-svelte-grid";
const { data, columns } = getData();

let table = $state();
</script>

<HeaderMenu api={table}>
<Grid {data} {columns} bind:this={table} />
</HeaderMenu>

To add the header context menu for specific columns, import the HeaderMenu component to the page (from the wx-svelte-grid package), wrap the Grid tag into the HeaderMenu tag. For the columns you want to show the menu, add the columns object with the required columns IDs to the HeaderMenu tag by setting their values to true . Don't forget to pass the api object to the HeaderMenu component.

<script>
import { getData } from "./common/data";
import { Grid, HeaderMenu } from "wx-svelte-grid";

const { data, columns } = getData();

let grid=$state();
</script>

<HeaderMenu api={grid} columns={{ city: true, firstName: true, id: true }} >
<Grid {data} {columns} bind:this={grid} />
</HeaderMenu>

Adding an Action menu

You can use the ActionMenu component with Grid. The next example shows how to add an icon to a cell and open the Action menu by clicking on it. To learn how to render components in Grid cells, refer to Adding custom content to cells.

First, we create the IconCell component with an icon. It's crucial to set the data-action-id attribute with row id to an HTML element so that the Action menu can be shown by clicking on it.

IconCell
<script>
let { row } = $props(); // access Grid api
</script>

<div class="table_icon" data-action-id={row.id}>
<i class="wxi-dots-h"></i>
</div>

<style>
.table_icon {
height: 20px;
cursor: pointer;
font-size: 18px;
text-align: center;
}
</style>

Then we apply the component to Grid cells. We import all necessary components: ActionMenu from wx-svelte-menu library, IconCell as well as defaultMenuOptions helper if we want to reuse default options set.

To open ActionMenu on icon click, we take the following steps:

  • set its dataKey to the same value as the data- attribute of an icon element
  • define its resolver function which returns a boolean value (true if we want to show the action menu for the row)

Finally, we use the handleClicks function to process menu actions and modify the Grid state accordingly.

<script>
import { Grid, defaultMenuOptions } from "wx-svelte-grid";
import { ActionMenu } from "wx-svelte-menu";
import IconCell from "../custom/IconCell.svelte";
import { getData } from "../data";

let api = $state();

const { data } = getData();

const columns = [
{ id: "menu", cell: IconCell, width: 50 },
{ id: "firstName", header: "First Name" },
{ id: "lastName", header: "Last Name" },
{ id: "email", header: "Email" },
];

const handleClicks = ev => {
const option = ev.action;
if (option) {
// clicking the icon also selects this row
const id = api.getState().selectedRows[0];
switch (option.id) {
case "add:before":
api.exec("add-row", { row: {}, before: id });
break;
case "add:after":
api.exec("add-row", { row: {}, after: id });
break;
case "copy":
api.exec("add-row", {
row: { ...api.getRow(id), id: null },
after: id,
});
break;
case "delete":
api.exec("delete-row", { id });
break;
}
}
};
</script>
<ActionMenu
resolver={id => id}
{api}
at={"point"}
dataKey={"actionId"}
options={defaultMenuOptions}
onclick={handleClicks}>
<Grid bind:this={api} {data} {columns} />
</ActionMenu>

Related articles: