---
name: cdp_select_dropdown
kind: function
lang: go
domain: browser
version: "1.0.0"
purity: impure
signature: "func CdpSelectDropdown(c *CDPConn, triggerSelector string, optionText string, opts CdpDropdownOpts) error"
description: "Selecciona una opcion en un DESPLEGABLE CUSTOM (combobox/listbox ARIA, react-select, MUI Select, headlessui, select2) — esos donde un <select> nativo NO aplica. Replica el patron de Playwright (que no tiene API para custom dropdowns): click REAL en el trigger (mousedown, no element.click JS), espera la apertura por polling (aria-expanded=true O [role=listbox]/[role=menu] visible O opciones con rect>0), localiza la opcion por texto normalizado (substring o exacto, case-insensitive) y hace click REAL en su centro, con verificacion suave (aria-expanded vuelve a false o Enter como fallback). Reusa CdpEvaluate, CdpClickXYHuman y CdpPressKey."
tags: [browser, chrome, cdp, automation, dropdown, combobox, listbox, aria, select, react-select, mui, headlessui, devtools]
uses_functions: [cdp_evaluate_go_browser, cdp_click_xy_human_go_browser, cdp_press_key_go_browser]
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [fmt, strings, time]
params:
  - name: c
    desc: "conexion CDP activa (*CDPConn)"
  - name: triggerSelector
    desc: "selector CSS del elemento que abre el desplegable (el boton/combobox sobre el que se hace click real)"
  - name: optionText
    desc: "texto visible de la opcion a elegir; se normaliza (trim + colapsar espacios) y se compara case-insensitive, por substring si opts.Exact=false o por igualdad si opts.Exact=true"
  - name: opts
    desc: "CdpDropdownOpts{Exact bool (igualdad vs substring, default substring); TimeoutMs int (espera apertura+opcion, default 3000); OptionRole string (rol ARIA de las opciones, default 'option' — usar 'menuitem' para menus, 'treeitem' para arboles)}"
output: "error si el trigger no existe, si el dropdown no abre dentro del timeout (\"el dropdown no abrio\"), o si la opcion no aparece (\"option %q not found in dropdown\"); nil si el click sobre la opcion se realizo (la verificacion de cierre es suave y no falla duro si queda ambigua)"
tested: false
tests: []
test_file_path: ""
file_path: "functions/browser/cdp_select_dropdown.go"
---

## Ejemplo

```go
conn, _ := CdpConnect(9222)
CdpNavigate(conn, "https://mui.com/material-ui/react-select/")

// Combobox MUI: el trigger es el div con role=combobox; el listbox monta y
// anima al abrir. CdpSelectDropdown clica el trigger, espera a que el listbox
// este visible y entonces clica la opcion "Twenty".
err := CdpSelectDropdown(conn, "[role=combobox]", "Twenty", CdpDropdownOpts{})
if err != nil {
    log.Fatal(err)
}

// react-select / headlessui: trigger por clase + match exacto + timeout amplio
// para listas que tardan en montar.
err = CdpSelectDropdown(conn, ".select__control", "España", CdpDropdownOpts{
    Exact:     true,
    TimeoutMs: 6000,
})

// Menu tipo dropdown-menu (no listbox): las opciones son role=menuitem.
err = CdpSelectDropdown(conn, "#user-menu-btn", "Cerrar sesion", CdpDropdownOpts{
    OptionRole: "menuitem",
})
```

## Cuando usarla

Usala cuando el desplegable NO es un `<select>` nativo: comboboxes/listboxes ARIA,
react-select, MUI Select, headlessui, select2, Ant Design, o cualquier menu hecho
con `<div>`/`<li>` + JS donde elegir = clicar el trigger y luego clicar la opcion
del menu desplegado. Es el equivalente al patron de Playwright
`click(trigger) -> getByRole('option', {name}) -> click(option)`, con la espera de
apertura ya resuelta. Para un `<select>` nativo de HTML usa `CdpSelectOption` (setea
`select.value` + dispara `input`/`change`), que es mas robusto y directo para ese
caso.

## Gotchas

- **Click real, no element.click()**: muchos dropdowns custom escuchan `mousedown`
  (no `click`), por eso esta funcion despacha eventos de raton reales sobre el
  centro del bbox. Solo cae a `element.click()` JS si el nodo no tiene geometria.
- **Animaciones de apertura**: el fallo nº1 reportado en Playwright es clicar la
  opcion ANTES de que el listbox monte/anime. Por eso hay polling de apertura
  (`dropdownWaitOpen`) que no avanza hasta que hay opciones visibles. Si tu
  dropdown anima muy lento, sube `TimeoutMs`.
- **Listas virtualizadas** (react-window, virtuoso): solo renderizan las opciones
  en viewport. Si la opcion buscada esta fuera del scroll inicial, puede que nunca
  se monte y la funcion devuelva "not found" aunque exista. Mitigacion: escribe en
  el combobox para filtrar (`CdpTypeText`) antes de llamar a esta funcion, o haz
  scroll dentro del listbox primero.
- **Trigger vs contenedor**: `triggerSelector` debe apuntar al elemento que ABRE el
  menu (el boton/combobox), no al `[role=listbox]` (que no existe hasta abrir).
- **Match de texto**: normaliza espacios y es case-insensitive; por defecto es
  substring (`Exact=false`). Si varias opciones comparten substring, elige la
  primera visible en orden de documento — usa `Exact=true` para desambiguar.
- **OptionRole**: por defecto `option` (`[role=option]`). Para menus de acciones usa
  `menuitem`; para arboles `treeitem`. La deteccion de apertura tambien considera
  `[role=menu]` y `li[role]` para cubrir patrones comunes.
- **Verificacion suave**: tras clicar, si el dropdown sigue abierto la funcion pulsa
  `Enter` como fallback y devuelve `nil`. No falla duro si la seleccion no se puede
  confirmar inequivocamente pero el click se hizo — comprueba el estado resultante
  (texto del trigger, valor del formulario) si necesitas certeza.
- **iframes**: opera en el documento principal (via `CdpEvaluate`). Para un dropdown
  dentro de un iframe necesitarias el contexto del frame (no cubierto aqui).
