Overview
Actions extend React Grab with custom functionality accessible from the context menu (right-click) or toolbar dropdown. Actions can perform operations like copying specific formats, opening files, triggering AI agents, or integrating with external tools.
Action Types
React Grab supports two types of actions:
Context Menu Actions - Appear in the right-click context menu when selecting elements
Toolbar Menu Actions - Appear in the toolbar dropdown menu
Context menu actions appear when right-clicking on selected elements:
Unique identifier for the action
Display label shown in the context menu
Set to "context-menu" or omit for context menu actions
Keyboard shortcut (single character) to trigger the action. Example: "C" for copy, "O" for open.
enabled
boolean | ((context: ActionContext) => boolean)
Whether the action is enabled. Can be a boolean or a function that receives the action context. Example: enabled : ( context ) => Boolean ( context . filePath )
onAction
(context: ContextMenuActionContext) => void | Promise<void>
required
Callback function executed when the action is triggered. The primary selected element
Array of all selected elements (for multi-selection)
Source file path of the element (if available)
Line number in the source file
Function to trigger the default copy action
enterPromptMode
(agent?: AgentOptions) => void
Function to enter prompt mode with optional agent configuration
Function to hide the context menu
Function to clean up and deactivate React Grab
performWithFeedback
(action: () => Promise<boolean>) => Promise<void>
Execute an action with visual feedback (loading/success/error states)
transformHtmlContent
(html: string, elements: Element[]) => Promise<string>
Transform HTML content before use
onOpenFile
(filePath: string, lineNumber?: number) => boolean | void
Handle file opening, return true to prevent default
transformOpenFileUrl
(url: string, filePath: string, lineNumber?: number) => string
Transform the file URL before opening
Optional AI agent configuration for this action. See Agent Providers for details.
Toolbar actions appear in the toolbar dropdown menu:
Unique identifier for the action
Display label shown in the toolbar menu
Must be set to "toolbar" for toolbar actions
Keyboard shortcut hint (not actively bound, just displayed)
enabled
boolean | (() => boolean)
Whether the action is enabled
Function to determine if the action is currently active (shown with a checkmark)
onAction
() => void | Promise<void>
required
Callback function executed when the action is triggered
Basic Action
A simple action that logs element information:
import type { Plugin } from "react-grab" ;
const inspectPlugin : Plugin = {
name: "inspect" ,
actions: [
{
id: "inspect" ,
label: "Inspect" ,
shortcut: "I" ,
onAction : ( context ) => {
console . log ( "Element:" , context . element );
console . log ( "Tag:" , context . tagName );
console . log ( "Component:" , context . componentName );
console . log ( "File:" , context . filePath , context . lineNumber );
context . hideContextMenu ();
},
},
],
};
Conditional Action
An action that’s only enabled when file path is available:
const openAction : ContextMenuAction = {
id: "open" ,
label: "Open in Editor" ,
shortcut: "O" ,
enabled : ( context ) => Boolean ( context . filePath ),
onAction : ( context ) => {
if ( ! context . filePath ) return ;
// Open file in editor
const url = `vscode://file ${ context . filePath } : ${ context . lineNumber || 1 } ` ;
window . open ( url , "_blank" );
context . hideContextMenu ();
context . cleanup ();
},
};
Action with Feedback
Use performWithFeedback for operations that take time:
const copyJsonAction : ContextMenuAction = {
id: "copy-json" ,
label: "Copy as JSON" ,
shortcut: "J" ,
onAction : async ( context ) => {
await context . performWithFeedback ( async () => {
// Extract element data
const data = {
tagName: context . tagName ,
component: context . componentName ,
attributes: Array . from ( context . element . attributes ). map ( attr => ({
name: attr . name ,
value: attr . value ,
})),
};
// Copy to clipboard
await navigator . clipboard . writeText ( JSON . stringify ( data , null , 2 ));
return true ; // Success
});
},
};
Toggle Action
A toolbar action that toggles a state:
import type { Plugin } from "react-grab" ;
const freezePlugin : Plugin = {
name: "freeze" ,
setup : ( api ) => {
let isFrozen = false ;
return {
actions: [
{
id: "toggle-freeze" ,
label: "Freeze UI" ,
target: "toolbar" ,
shortcut: "F" ,
isActive : () => isFrozen ,
onAction : () => {
isFrozen = ! isFrozen ;
api . setOptions ({
freezeReactUpdates: isFrozen ,
});
},
},
],
};
},
};
Action with Selection
Toolbar action that activates React Grab and waits for element selection:
const copyHtmlToolbarAction : ToolbarMenuAction = {
id: "copy-html-toolbar" ,
label: "Copy HTML" ,
target: "toolbar" ,
onAction : () => {
// This pattern is used by built-in plugins
isPendingSelection = true ;
api . activate ();
// Then in the plugin hooks:
// onElementSelect: (element) => {
// if (!isPendingSelection) return;
// isPendingSelection = false;
// // Perform action with element
// return true; // Prevent default
// }
},
};
Complete Action Plugin Example
Here’s a complete plugin with both context menu and toolbar actions:
import type { Plugin } from "react-grab" ;
const devToolsPlugin : Plugin = {
name: "dev-tools" ,
setup : ( api ) => {
let isPendingScreenshot = false ;
return {
hooks: {
onElementSelect : async ( element ) => {
if ( ! isPendingScreenshot ) return ;
isPendingScreenshot = false ;
// Take screenshot of element
const canvas = await html2canvas ( element );
canvas . toBlob (( blob ) => {
if ( blob ) {
navigator . clipboard . write ([
new ClipboardItem ({ "image/png" : blob }),
]);
}
});
return true ;
},
onDeactivate : () => {
isPendingScreenshot = false ;
},
},
actions: [
// Context menu actions
{
id: "copy-selector" ,
label: "Copy CSS Selector" ,
shortcut: "S" ,
onAction : async ( context ) => {
const selector = getCssSelector ( context . element );
await navigator . clipboard . writeText ( selector );
context . hideContextMenu ();
},
},
{
id: "copy-xpath" ,
label: "Copy XPath" ,
shortcut: "X" ,
onAction : async ( context ) => {
const xpath = getXPath ( context . element );
await navigator . clipboard . writeText ( xpath );
context . hideContextMenu ();
},
},
// Toolbar actions
{
id: "screenshot" ,
label: "Screenshot Element" ,
target: "toolbar" ,
onAction : () => {
isPendingScreenshot = true ;
api . activate ();
},
},
{
id: "log-state" ,
label: "Log React Grab State" ,
target: "toolbar" ,
onAction : () => {
console . log ( api . getState ());
},
},
],
};
},
};
Action Best Practices
Unique IDs : Use descriptive, unique action IDs to avoid conflicts
Hide Menu : Always call context.hideContextMenu() after completing context menu actions
Cleanup : Call context.cleanup() when deactivating React Grab
Feedback : Use performWithFeedback for async operations to show loading states
Shortcuts : Use single-character shortcuts that don’t conflict with built-in actions
Conditional Enable : Use the enabled function to disable actions when not applicable
Error Handling : Wrap async operations in try/catch blocks
Built-in Action Shortcuts
Avoid conflicting with these built-in shortcuts:
C - Copy
O - Open in editor
Enter - Comment/prompt mode
See Also