""" Example of implementing hover functionality for elements. This shows how to hover over elements to trigger hover states and tooltips. """ import asyncio import os import sys from typing import Optional sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) from dotenv import load_dotenv from pydantic import BaseModel load_dotenv() from browser_use.agent.service import Agent, Controller from browser_use.agent.views import ActionResult from browser_use.browser import BrowserSession from browser_use.llm import ChatOpenAI # Initialize controller controller = Controller() class HoverAction(BaseModel): """Parameters for hover action""" index: Optional[int] = None xpath: Optional[str] = None selector: Optional[str] = None @controller.registry.action( 'Hover over an element', param_model=HoverAction, # Define this model with at least "index: int" field ) async def hover_element(params: HoverAction, browser_session: BrowserSession): """ Hovers over the element specified by its index from the cached selector map or by XPath. """ try: element_node = None if params.xpath: # Find element by XPath using CDP cdp_session = await browser_session.get_or_create_cdp_session() result = await cdp_session.cdp_client.send.Runtime.evaluate( params={ 'expression': f""" (() => {{ const element = document.evaluate('{params.xpath}', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (element) {{ const rect = element.getBoundingClientRect(); return {{found: true, x: rect.x + rect.width/2, y: rect.y + rect.height/2}}; }} return {{found: false}}; }})() """, 'returnByValue': True }, session_id=cdp_session.session_id ) element_info = result.get('result', {}).get('value', {}) if not element_info.get('found'): raise Exception(f'Failed to locate element with XPath {params.xpath}') x, y = element_info['x'], element_info['y'] elif params.selector: # Find element by CSS selector using CDP cdp_session = await browser_session.get_or_create_cdp_session() result = await cdp_session.cdp_client.send.Runtime.evaluate( params={ 'expression': f""" (() => {{ const element = document.querySelector('{params.selector}'); if (element) {{ const rect = element.getBoundingClientRect(); return {{found: true, x: rect.x + rect.width/2, y: rect.y + rect.height/2}}; }} return {{found: false}}; }})() """, 'returnByValue': True }, session_id=cdp_session.session_id ) element_info = result.get('result', {}).get('value', {}) if not element_info.get('found'): raise Exception(f'Failed to locate element with CSS Selector {params.selector}') x, y = element_info['x'], element_info['y'] elif params.index is not None: # Use index to locate the element selector_map = await browser_session.get_selector_map() if params.index not in selector_map: raise Exception(f'Element index {params.index} does not exist - retry or use alternative actions') element_node = selector_map[params.index] # Get element position if not element_node.absolute_position: raise Exception(f'Element at index {params.index} has no position information') x = element_node.absolute_position.x + element_node.absolute_position.width / 2 y = element_node.absolute_position.y + element_node.absolute_position.height / 2 else: raise Exception('Either index, xpath, or selector must be provided') # Perform hover using CDP mouse events cdp_session = await browser_session.get_or_create_cdp_session() # Move mouse to the element position await cdp_session.cdp_client.send.Input.dispatchMouseEvent( params={ 'type': 'mouseMoved', 'x': x, 'y': y, }, session_id=cdp_session.session_id ) # Wait a bit for hover state to trigger await asyncio.sleep(0.1) msg = ( f'🖱️ Hovered over element at index {params.index}' if params.index is not None else f'🖱️ Hovered over element with XPath {params.xpath}' if params.xpath else f'🖱️ Hovered over element with selector {params.selector}' ) return ActionResult(extracted_content=msg, include_in_memory=True) except Exception as e: error_msg = f'❌ Failed to hover over element: {str(e)}' return ActionResult(error=error_msg) async def main(): """Main function to run the example""" browser_session = BrowserSession() await browser_session.start() llm = ChatOpenAI(model='gpt-4.1') # Create the agent with hover capability agent = Agent( task=""" Go to a website with hover interactions, like https://www.w3schools.com/howto/howto_css_dropdown.asp Try hovering over the dropdown menu to see the dropdown items appear. Then describe what happens when you hover. """, llm=llm, browser_session=browser_session, controller=controller, ) # Run the agent await agent.run(max_steps=10) # Cleanup await browser_session.kill() if __name__ == '__main__': asyncio.run(main())