Hide/Delete Menu Items in Frappe Forms and List Views

Hide/Delete Menu Items in Frappe Forms and List Views


Sometimes we need to prevent users from accessing certain actions from the menu, such as Delete, Rename, or any custom menu item.

Frappe does not provide a standard client-side API for hiding every menu item. However, since menu items are rendered in the page DOM, we can use jQuery selectors to locate and remove them after the page is loaded.

This approach is commonly used in Client Scripts and custom JavaScript files.


1. Hide Menu Items in Form View

Code

frappe.ui.form.on('Sales Order', {
    refresh(frm) {
        const items_to_hide = ['Delete'];

        items_to_hide.forEach(label => {
            const $item = frm.page.menu.find(
                `li:has(.menu-item-label:contains("${label}"))`
            );

            if ($item.length) {
                $item.remove();
            }
        });
    }
});

How it Works

During the refresh event:

  1. Access the form menu using:
frm.page.menu
  1. Search for menu items containing the specified label.
li:has(.menu-item-label:contains("Delete"))
  1. Remove the matching menu item from the DOM.
$item.remove();

Result

Before:

Menu
 ├─ Rename
 ├─ Duplicate
 ├─ Delete
 └─ Print

After:

Menu
 ├─ Rename
 ├─ Duplicate
 └─ Print

2. Hide Menu Items in List View

Code

frappe.listview_settings['Sales Order'] = {
    refresh(listview) {

        const items_to_hide = ['Delete'];

        items_to_hide.forEach(label => {
            const $item = listview.page.actions.find(
                `li:has(.menu-item-label:contains("${label}"))`
            );

            if ($item.length) {
                $item.remove();
            }
        });
    }
};

How it Works

In List View, action buttons are rendered inside:

listview.page.actions

The script:

  1. Locates the Actions dropdown.
  2. Searches for the specified menu item.
  3. Removes it from the DOM.

Hide Multiple Menu Items

Instead of hiding only Delete, we can hide multiple items.

const items_to_hide = [
    'Delete',
    'Rename',
    'Duplicate'
];

The same logic will remove all matching entries.


Conditional Hiding

You can hide menu items only for specific users or roles.

Example:

if (!frappe.user.has_role('System Manager')) {

    const items_to_hide = ['Delete'];

    items_to_hide.forEach(label => {
        const $item = frm.page.menu.find(
            `li:has(.menu-item-label:contains("${label}"))`
        );

        if ($item.length) {
            $item.remove();
        }
    });
}

Important Note

This is a UI-level customization only.

Removing the menu item:

$item.remove();

does not remove backend permissions.

If a user still has Delete permission, they may be able to delete records through:

  • API calls
  • Custom scripts
  • Other entry points

For proper security, always configure permissions using:

Role Permission Manager

or

User Permissions

The UI customization should be treated as a usability enhancement, not a security mechanism.


Recommended Use Cases

  • Hide Delete for operational users.
  • Hide Rename on master data.
  • Hide Duplicate when document duplication is not allowed.
  • Simplify the menu for end users.
  • Remove custom menu items based on business rules.

Summary

Form View:

frm.page.menu.find(...)

List View:

listview.page.actions.find(...)

Remove menu item:

$item.remove();

Hide multiple items:

const items_to_hide = [
    'Delete',
    'Rename',
    'Duplicate'
];

Always remember:

Hiding a menu item improves the user experience, but actual access control must be enforced through Frappe permissions.

1 Like