Using Context Menus
The easiest way to configure a context menu is to provide the getCellContextMenuItems
callback function and use it to return the menu items you want to show in the context menu.
const getCellContextMenuItems = ({ column, value }) => {
if (column.id === 'currency') {
return [
{
label: `Convert ${value}`,
key: 'currency-convert',
},
];
}
if (column.id === 'age') {
return null;
}
return [
{
label: `Welcome ${value}`,
key: 'hi',
},
];
};
<DataSource<Developer> data={data} primaryKey="id">
<InfiniteTable<Developer>
getCellContextMenuItems={getCellContextMenuItems}
columns={columns}
/>
</DataSource>
Right-click any cell in the table to see the custom context menu.
import { InfiniteTable, DataSource, InfiniteTablePropColumns, } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource = () => { return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/developers100') .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { stack: { field: 'stack', header: 'Stack', }, firstName: { field: 'firstName', header: 'Name', }, age: { field: 'age', header: 'Age', }, hobby: { field: 'hobby', header: 'Hobby', }, preferredLanguage: { header: 'Language', field: 'preferredLanguage', }, }; export default function App() { return ( <> <DataSource<Developer> primaryKey="id" data={dataSource}> <InfiniteTable<Developer> columns={columns} getCellContextMenuItems={({ data, column }) => { return [ { key: 'hello', label: `Hello, ${data?.lastName} ${data?.firstName}`, onClick: () => { alert(`Hello, ${data?.lastName} ${data?.firstName}`); }, }, { key: 'col', label: `Current clicked column: ${column.header}`, }, { key: 'learn', label: `Learn`, menu: { items: [ { key: 'backend', label: 'Backend', onClick: () => { alert( `Learn Backend, ${data?.lastName} ${data?.firstName}`, ); }, }, { key: 'frontend', label: 'Frontend', onClick: () => { alert( `Learn Frontend, ${data?.lastName} ${data?.firstName}`, ); }, }, ], }, }, ]; }} /> </DataSource> </>
Note
The getCellContextMenuItems
function can return one of the following:
null
- no custom context menu will be displayed, the default context menu will be shown (default event behavior not prevented)[]
- an empty array - no custom context menu will be displayed, but the default context menu is not shown - the default event behavior is preventedArray<MenuItem>
- an array of menu items to be displayed in the context menu - eachMenuItem
should have:- a unique
key
property, - a
label
property with the value to display in the menu cell - it's calledlabel
because this is the name of the default column in the context menu - an optional
onClick
callback function to handle the click event on the menu item.
- a unique
In addition, if you need to configure the context menu to have other columns rather than the default column (named label
), you can do so by returning an object with columns
and items
:
const getCellContextMenuItems = () => {
return {
columns: [{ name: 'label' }, { name: 'lcon' }],
items: [
{
label: 'Welcome',
icon: '👋',
key: 'hi',
onAction: () => {
// do something
},
hideMenuOnAction: true,
},
{
label: 'Convert',
icon: '🔁',
key: 'convert',
},
],
};
};
Right-click any cell in the table to see a context menu with multiple columns (icon
, label
and description
).
import { InfiniteTable, DataSource, InfiniteTablePropColumns, } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource = () => { return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/developers100') .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { stack: { field: 'stack', header: 'Stack', }, firstName: { field: 'firstName', header: 'Name', }, age: { field: 'age', header: 'Age', }, hobby: { field: 'hobby', header: 'Hobby', }, preferredLanguage: { header: 'Language', field: 'preferredLanguage', }, }; export default function App() { return ( <> <DataSource<Developer> primaryKey="id" data={dataSource}> <InfiniteTable<Developer> columns={columns} columnDefaultEditable getCellContextMenuItems={({ data, column }) => { const columns = [ { name: 'icon' }, { name: 'label' }, { name: 'description' }, ]; return { columns, items: [ { key: 'hello', icon: '👋', label: `Hello, ${data?.lastName} ${data?.firstName}`, description: `This is a description for ${data?.lastName}`, onClick: () => { alert(`Hello, ${data?.lastName} ${data?.firstName}`); }, }, { key: 'col', icon: '🙌', label: `Column: ${column.header}`, description: `Current clicked column: ${column.header}`, }, { key: 'learn', icon: '📚', label: `Learn`, description: `Learn more about ${data?.preferredLanguage}`, menu: { columns, items: [ { key: 'backend', label: 'Backend', icon: '👨💻', description: 'In the Backend', onClick: () => { alert( `Learn Backend, ${data?.lastName} ${data?.firstName}`, ); }, }, { key: 'frontend', label: 'Frontend', icon: '👨💻', description: 'In the Frontend', onClick: () => { alert( `Learn Frontend, ${data?.lastName} ${data?.firstName}`, ); }, }, ], }, }, ], }; }} /> </DataSource> </>
Context Menus for the Table Body
You might want to show a context menu for the table body, when the user right-clicks outside of any existing cell.
For this, you can use the getContextMenuItems
prop.
This function has almost the same signature as getCellContextMenuItems
, with the following differences in the object passed as first parameter:
- all cell-related properties (
column
,data
,value
, etc) can beundefined
- it contains an
event
property with the original event object for the right-click event
Right-click outside cells in the table to see a context menu for the table body.
import { InfiniteTable, DataSource, InfiniteTablePropColumns, } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource = () => { return fetch('https://infinite-table.com/.netlify/functions/json-server' + '/developers100') .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns<Developer> = { firstName: { field: 'firstName', header: 'Name', defaultWidth: 120, }, age: { field: 'age', header: 'Age', defaultWidth: 100, }, preferredLanguage: { header: 'Language', defaultWidth: 120, field: 'preferredLanguage', }, }; export default function App() { return ( <> <DataSource<Developer> primaryKey="id" data={dataSource}> <InfiniteTable<Developer> columns={columns} getContextMenuItems={({ data, column }) => { if (!data) return [ { key: 'add', label: 'Add Item', onClick: () => { alert('Add Item'); }, }, ]; return [ { key: 'hello', label: `Hello, ${data?.lastName} ${data?.firstName}`, onClick: () => { alert(`Hello, ${data?.lastName} ${data?.firstName}`); }, }, { key: 'col', label: `Current clicked column: ${column?.header}`, }, { key: 'learn', label: `Learn`, menu: { items: [ { key: 'backend', label: 'Backend', onClick: () => { alert( `Learn Backend, ${data?.lastName} ${data?.firstName}`, ); }, }, { key: 'frontend', label: 'Frontend', onClick: () => { alert( `Learn Frontend, ${data?.lastName} ${data?.firstName}`, ); }, }, ], }, }, ]; }} /> </DataSource> </>
Hiding the Context Menu
To hide the context menu when you click a menu item, you can use the hideMenuOnAction
property on the menu item.
Alternatively, you can use the object passed in as a parameter to the item.onAction
callback function to hide the menu:
const getCellContextMenuItems = () => {
return {
items: [
{
label: 'Hello',
key: 'hi',
onAction: ({ key, hideMenu }) => {
// do something
console.log('Hello');
// hide the menu
hideMenu();
},
},
],
};
};
The third option is to use the hideContextMenu
function in the API.