Skip to main content

Interactive Functions

Functions that require user interaction or wait for events.

selectElement

Interactive element picker - user clicks to select.

window.__devtool.selectElement()

Parameters: None

Returns: Promise that resolves when user clicks:

{
selector: "#user-avatar",
element: {
tag: "img",
id: "user-avatar",
classes: ["avatar", "rounded"],
attributes: {src: "/images/user.png", alt: "User"}
},
position: {x: 150, y: 200},
path: "html > body > header > div.user-info > img#user-avatar"
}

When cancelled (Escape key):

{
cancelled: true,
message: "Selection cancelled by user"
}

User Experience:

  • Cursor changes to crosshair
  • Hovered elements are highlighted
  • Click to select
  • Press Escape to cancel

Example via MCP:

proxy {action: "exec", id: "app", code: "window.__devtool.selectElement()"}

The exec waits for the Promise to resolve.

measureBetween

Measure the distance between two elements.

window.__devtool.measureBetween(selector1, selector2)

Parameters:

  • selector1 (string): CSS selector for first element
  • selector2 (string): CSS selector for second element

Returns:

{
distance: {
x: 0,
y: 150,
diagonal: 150
},
direction: "below",
gap: {
horizontal: 0,
vertical: 100 // Empty space between elements
},
element1: {
center: {x: 400, y: 100},
bounds: {top: 50, left: 300, width: 200, height: 100}
},
element2: {
center: {x: 400, y: 350},
bounds: {top: 250, left: 300, width: 200, height: 200}
}
}

Direction values:

  • "above", "below", "left", "right"
  • "above-left", "above-right", "below-left", "below-right"
  • "overlapping" (centers are at same position)

Example:

window.__devtool.measureBetween('#header', '#footer')
{distance: {y: 850}, gap: {vertical: 800}, direction: "below"}

waitForElement

Wait for an element to appear in the DOM.

window.__devtool.waitForElement(selector, timeout)

Parameters:

  • selector (string): CSS selector to wait for
  • timeout (number, optional): Maximum wait time in ms (default: 5000)

Returns: Promise that resolves when element appears:

{
found: true,
element: {
tag: "div",
classes: ["loading-complete"],
id: ""
},
waited: 1234 // milliseconds
}

When timeout:

{
found: false,
timeout: true,
waited: 5000,
message: "Element not found within 5000ms"
}

Example:

// Wait for loading to complete
await window.__devtool.waitForElement('.data-loaded', 10000)

// Then inspect the content
window.__devtool.inspect('.data-content')

How it works:

  • Uses MutationObserver for efficiency
  • Checks immediately first
  • No polling - responds as soon as element appears

ask

Show a modal dialog to ask the user a question.

window.__devtool.ask(question, options, config)

Parameters:

  • question (string): The question to display
  • options (string[]): Array of answer options
  • config (object, optional): Configuration

Config Options:

OptionTypeDefaultDescription
timeoutnumber30000Auto-dismiss timeout in ms
allowCancelbooleantrueShow cancel button
defaultOptionnumbernullPre-selected option index

Returns: Promise that resolves with user selection:

{
answer: "Option A",
index: 0,
cancelled: false
}

When cancelled:

{
answer: null,
index: null,
cancelled: true
}

When timeout:

{
answer: null,
index: null,
timeout: true
}

Examples:

Simple yes/no:

window.__devtool.ask('Is this the correct element?', ['Yes', 'No'])

Multiple options:

window.__devtool.ask('Which layout looks better?', [
'Grid layout',
'Flex layout',
'Table layout',
'None of these'
])

With timeout:

window.__devtool.ask('Continue with changes?', ['Yes', 'No'], {
timeout: 10000
})

User Experience:

  • Modal appears centered on screen
  • Click option button to select
  • Click cancel or press Escape to dismiss
  • Auto-dismisses after timeout

Common Patterns

Interactive Element Selection Workflow

// Let user select element
const selected = await window.__devtool.selectElement()
if (selected.cancelled) {
console.log('User cancelled selection')
return
}

// Inspect the selected element
const info = window.__devtool.inspect(selected.selector)

// Ask what to do
const action = await window.__devtool.ask('What would you like to do?', [
'Show layout',
'Check accessibility',
'Measure from here'
])

if (action.answer === 'Show layout') {
window.__devtool.showLayout()
} else if (action.answer === 'Check accessibility') {
const a11y = window.__devtool.getA11yInfo(selected.selector)
console.log(a11y)
} else if (action.answer === 'Measure from here') {
const second = await window.__devtool.selectElement()
const measure = window.__devtool.measureBetween(selected.selector, second.selector)
console.log(measure)
}

Wait for Dynamic Content

// Click a button that loads content
document.querySelector('#load-data').click()

// Wait for content to appear
const result = await window.__devtool.waitForElement('.data-container', 10000)

if (result.found) {
// Now safe to inspect
const data = window.__devtool.inspect('.data-container')
console.log(`Loaded in ${result.waited}ms`)
}

Spacing Verification

// Measure spacing between elements
const headerToNav = window.__devtool.measureBetween('#header', '#nav')
const navToContent = window.__devtool.measureBetween('#nav', '#content')

console.log('Header to nav gap:', headerToNav.gap.vertical, 'px')
console.log('Nav to content gap:', navToContent.gap.vertical, 'px')

// Check consistency
if (headerToNav.gap.vertical !== navToContent.gap.vertical) {
console.warn('Inconsistent spacing!')
}

User Confirmation Before Changes

// Show what will change
window.__devtool.highlight('.affected-elements', {color: 'yellow', duration: 0})

// Ask for confirmation
const confirm = await window.__devtool.ask(
'These elements will be modified. Proceed?',
['Yes, proceed', 'No, cancel'],
{timeout: 60000}
)

window.__devtool.clearAllOverlays()

if (confirm.answer === 'Yes, proceed') {
// Make changes
} else {
console.log('User cancelled')
}

Multi-Step Selection

async function measureMultiple() {
const points = []

while (true) {
const action = await window.__devtool.ask(
`${points.length} points selected. What next?`,
['Add point', 'Finish', 'Cancel']
)

if (action.answer === 'Cancel' || action.cancelled) {
return null
}

if (action.answer === 'Finish') {
break
}

const point = await window.__devtool.selectElement()
if (!point.cancelled) {
points.push(point)
window.__devtool.highlight(point.selector, {
label: `Point ${points.length}`,
duration: 0
})
}
}

return points
}

See Also