Skip to main content

ContextMenuAction

Defines a custom action that appears in the context menu when elements are selected.

Properties

id
string
required
Unique identifier for this action. Used for deduplication and tracking.
label
string
required
Display text shown in the context menu.
target
'context-menu'
Optional target specification. Use “context-menu” to explicitly mark this as a context menu action.
shortcut
string
Keyboard shortcut hint displayed next to the action. Example: “⌘K” or “Ctrl+K”.
enabled
boolean | ((context: ActionContext) => boolean)
Whether this action is enabled. Can be a boolean or a function that receives the action context and returns a boolean. Disabled actions appear greyed out.
onAction
(context: ContextMenuActionContext) => void | Promise<void>
required
Called when the action is triggered. Receives the action context with element data and helper functions.
agent
AgentOptions
Optional agent configuration. When provided, this action can trigger AI-assisted operations. See AgentOptions.

ToolbarMenuAction

Defines a custom action that appears in the toolbar dropdown menu.

Properties

id
string
required
Unique identifier for this action.
label
string
required
Display text shown in the toolbar menu.
shortcut
string
Keyboard shortcut hint. Example: “⌘K” or “Ctrl+K”.
target
'toolbar'
required
Must be “toolbar” to identify this as a toolbar action.
enabled
boolean | (() => boolean)
Whether this action is enabled. Can be a boolean or a function that returns a boolean.
isActive
() => boolean
Function that returns whether this action is currently active. Active actions are visually highlighted.
onAction
() => void | Promise<void>
required
Called when the action is triggered. No context is provided for toolbar actions.

ActionContext

Context object passed to action handlers with information about selected elements and helper functions.

Properties

element
Element
required
The primary selected element. If multiple elements are selected, this is typically the first one.
elements
Element[]
required
Array of all selected elements.
filePath
string
File path where the element’s component is defined.
lineNumber
number
Line number where the element’s component is defined.
componentName
string
Name of the React component for this element.
tagName
string
HTML tag name of the element (lowercase).
enterPromptMode
(agent?: AgentOptions) => void
Function to enter prompt mode for AI-assisted operations. Optionally pass agent configuration.
hooks
ActionContextHooks
required
Helper hooks for common operations. See ActionContextHooks.
performWithFeedback
(action: () => Promise<boolean>) => Promise<void>
required
Execute an async action with visual feedback. Shows success/error flash based on return value.
  • Return true for success (shows success flash)
  • Return false for failure (shows error state)
  • Throws errors are caught and shown as errors
hideContextMenu
() => void
required
Programmatically hide the context menu.
cleanup
() => void
required
Clean up any temporary state or UI elements. Call before exiting action.

ContextMenuActionContext

Extends ActionContext with additional context menu-specific functionality.

Properties

Inherits all properties from ActionContext plus:
copy
() => void
Helper function to copy selected elements to clipboard using default behavior.

ActionContextHooks

Helper hooks provided in the action context for common operations.

Properties

transformHtmlContent
(html: string, elements: Element[]) => Promise<string>
required
Transform HTML content through all registered plugin transform hooks.
onOpenFile
(filePath: string, lineNumber?: number) => boolean | void
required
Trigger file opening with plugin hooks. Returns false if opening was prevented.
transformOpenFileUrl
(url: string, filePath: string, lineNumber?: number) => string
required
Transform file opening URL through all registered plugin hooks.

Usage

Basic Context Menu Action

import { ContextMenuAction } from 'react-grab';

const logAction: ContextMenuAction = {
  id: 'log-element',
  label: 'Log to Console',
  shortcut: '⌘L',
  onAction: (context) => {
    console.log('Selected element:', context.element);
    console.log('Tag:', context.tagName);
    console.log('Component:', context.componentName);
    console.log('Total selected:', context.elements.length);
  }
};

Conditional Action Enabling

const openFileAction: ContextMenuAction = {
  id: 'open-file',
  label: 'Open in Editor',
  enabled: (context) => {
    // Only enable if we have file location info
    return !!context.filePath;
  },
  onAction: (context) => {
    if (context.filePath) {
      context.hooks.onOpenFile(context.filePath, context.lineNumber);
    }
  }
};

Action with Feedback

const saveAction: ContextMenuAction = {
  id: 'save-snippet',
  label: 'Save Snippet',
  onAction: async (context) => {
    await context.performWithFeedback(async () => {
      const content = await getElementContent(context.element);
      const success = await saveToDatabase(content);
      return success; // true = success flash, false = error
    });
    
    context.cleanup();
  }
};

Action with AI Agent

import { myAgent } from './agent';

const refactorAction: ContextMenuAction = {
  id: 'refactor',
  label: 'Refactor with AI',
  agent: {
    provider: myAgent,
    onComplete: (session, elements) => {
      console.log('Refactoring complete!');
    }
  },
  onAction: (context) => {
    // Automatically enters prompt mode with the configured agent
    context.enterPromptMode?.();
  }
};

Toolbar Action

import { ToolbarMenuAction } from 'react-grab';

let debugMode = false;

const toggleDebugAction: ToolbarMenuAction = {
  id: 'toggle-debug',
  label: 'Debug Mode',
  target: 'toolbar',
  shortcut: '⌘D',
  isActive: () => debugMode,
  onAction: () => {
    debugMode = !debugMode;
    console.log('Debug mode:', debugMode ? 'ON' : 'OFF');
  }
};

Action with Copy Helper

const customCopyAction: ContextMenuAction = {
  id: 'copy-with-metadata',
  label: 'Copy with Metadata',
  onAction: async (context) => {
    // First use default copy
    context.copy?.();
    
    // Then add metadata to clipboard
    const metadata = {
      component: context.componentName,
      file: context.filePath,
      line: context.lineNumber,
      count: context.elements.length
    };
    
    await navigator.clipboard.writeText(
      JSON.stringify(metadata, null, 2)
    );
  }
};

Action with Transform Hook

const exportHtmlAction: ContextMenuAction = {
  id: 'export-html',
  label: 'Export HTML',
  onAction: async (context) => {
    await context.performWithFeedback(async () => {
      const html = context.element.outerHTML;
      
      // Transform through plugin hooks
      const transformed = await context.hooks.transformHtmlContent(
        html,
        context.elements
      );
      
      // Save to file
      const success = await downloadFile(
        'export.html',
        transformed
      );
      
      return success;
    });
  }
};

Registering Actions via Plugin

import { Plugin } from 'react-grab';

const myPlugin: Plugin = {
  name: 'my-plugin',
  actions: [
    logAction,
    openFileAction,
    saveAction,
    toggleDebugAction
  ]
};

// Register plugin to add actions
reactGrab.registerPlugin(myPlugin);

Type Definitions

export interface ContextMenuAction {
  id: string;
  label: string;
  target?: 'context-menu';
  shortcut?: string;
  enabled?: boolean | ((context: ActionContext) => boolean);
  onAction: (context: ContextMenuActionContext) => void | Promise<void>;
  agent?: AgentOptions;
}

export interface ToolbarMenuAction {
  id: string;
  label: string;
  shortcut?: string;
  target: 'toolbar';
  enabled?: boolean | (() => boolean);
  isActive?: () => boolean;
  onAction: () => void | Promise<void>;
}

export interface ActionContext {
  element: Element;
  elements: Element[];
  filePath?: string;
  lineNumber?: number;
  componentName?: string;
  tagName?: string;
  enterPromptMode?: (agent?: AgentOptions) => void;
  hooks: ActionContextHooks;
  performWithFeedback: (action: () => Promise<boolean>) => Promise<void>;
  hideContextMenu: () => void;
  cleanup: () => void;
}

export interface ContextMenuActionContext extends ActionContext {
  copy?: () => void;
}

export interface ActionContextHooks {
  transformHtmlContent: (html: string, elements: Element[]) => Promise<string>;
  onOpenFile: (filePath: string, lineNumber?: number) => boolean | void;
  transformOpenFileUrl: (url: string, filePath: string, lineNumber?: number) => string;
}

See Also

  • Plugin - Register actions via plugins
  • Agent - Configure AI agents for actions

Build docs developers (and LLMs) love