0249
Inputs / Form fields Creacion Revision

Select · single value

Publicado
Lectura
5 min

El Select es la respuesta a una pregunta cerrada. Su desafío no es visual sino combinatorio: cómo presentar entre tres y cien opciones de forma que el usuario encuentre la suya en menos de dos segundos, sin perder accesibilidad, sin reinventar el control nativo cuando este basta. Esta ficha documenta el contrato del Select en mayo de 2026.

Decomposición del componente

Las seis capas del componente

01 · Átomo color.neutral.950 · color.neutral.200 · space.10 · space.8 · radius.sm · duration.140

Primitivos compartidos con el resto de inputs. El Select no inventa.

02 · Compuesto color.surface.input.bg · color.surface.menu.bg · color.surface.menu.option-hover · space.menu.option.y · motion.menu.expand

Semánticos: fondo del control, fondo del menú desplegado, hover de opción, padding de cada item, animación del expand.

03 · Regla native-first policy · combobox WAI-ARIA 1.2 · Zod enum · Floating UI para posicionamiento

Governance: si el listado ≤12 opciones usa <select> nativo; si supera, combobox custom con pattern completo (aria-expanded, aria-controls, aria-activedescendant).

04 · Pieza <Select options={enum} value={x} />

Schema cerrado sobre enum. Un agente que proponga un value fuera del enum recibe rechazo OPA.

05 · Familia Inputs / Form fields · emparentado con Combobox editable y MultiSelect

El Select single-value es el canon. Los parientes (Combobox editable, MultiSelect) se bifurcan con schema y governance propios.

06 · Estado reposo · hover · focus-visible · open · searchable · multi · loading · disabled · agent-aware

open y searchable son los estados que más varían; multi se activa solo en la variant MultiSelect.

Tokens consumidos

Semánticos

color.surface.input.bg oklch(0.99 0.005 75)

Fondo del control en reposo

color.surface.menu.bg oklch(0.97 0.01 75)

Fondo del menú desplegado, ligero offset visual

color.surface.menu.option-hover oklch(0.92 0.01 75)

Estado hover de cada opción del menú

color.border.input.default oklch(0.78 0.005 75)

Borde unificado con resto de inputs

space.menu.option.y 0.5rem

Padding vertical de cada opción, hit-target 44px

motion.menu.expand { duration: 140ms, easing: cubic-bezier(0.2, 0, 0.38, 1) }

Expansión del menú, deshabilitada con prefers-reduced-motion

Técnicas de governance aplicadas

Técnicas activas

Native-first

Herramienta
<select> HTML cuando el listado no excede 12 opciones
Cobertura
Decisión en design system policy

Por defecto el componente renderiza <select> nativo. Solo cuando hay búsqueda, agrupación, o más de 12 opciones, se promueve a combobox custom WAI-ARIA. La regla evita reinventar accesibilidad en el 80% de los casos.

Combobox WAI-ARIA

Herramienta
ARIA Authoring Practices 1.2 + Floating UI
Cobertura
14 estados covered

Cuando el listado supera el umbral, el componente custom implementa el patrón combobox completo: aria-expanded, aria-controls, aria-activedescendant, navegación con flechas, búsqueda por tecla, escape para cerrar.

Schema enumerado

Herramienta
Zod enum + JSON Schema oneOf
Cobertura
Cierre estricto del rango de valores aceptados

Un agente que componga un Select tiene que elegir un valor del enum. Si propone uno fuera, OPA rechaza. La governance rompe la tentación clásica de los LLM de inventar opciones plausibles.

Estado físico

Agentic-consumable desde noviembre de 2025. Las opciones se exponen vía MCP como enum cerrado. El agente no puede ampliar el rango sin un cambio governance-firmado.

Estados soportados

hover, focus-visible, disabled, loading (durante carga asíncrona de opciones), multi-select (variant), searchable (variant), agent-aware. El estado searchable se activa automáticamente cuando el rango supera 12 opciones.

Composiciones prohibidas

Reglas activas

value fuera del enum

Herramienta
OPA · block level
Cobertura
Schema del rango

Un agente no puede componer <Select value='beta-custom'> si beta-custom no está en options. La alternativa: ampliar el enum vía change request governance-firmado.

Más de 12 opciones en <select> nativo

Herramienta
OPA · warning
Cobertura
Umbral de promoción

Se promueve a combobox custom con búsqueda. Warning en CI si la composición ignora la regla.

Select con opciones vacías

Herramienta
OPA · block level
Cobertura
Schema mínimo

Un Select con 0 o 1 opción no tiene sentido semántico. Alternativa: texto estático, o Input readonly si el valor es informativo.

Interoperabilidad

  • Consumido por: FormRow, InlineFilters, Toolbar (como selector de vista), SettingsPanel.
  • Consume: Label, HelperText, internamente Option (no exportable; es la unidad del enum).
  • Con qué compone mal: dentro de Tooltip (el menú del Select se abre dentro del tooltip, colisiona con el dismiss), y como hijo directo de Modal si el menú excede el viewport del modal.
  • Sustituibles por: Radio si hay ≤5 opciones y el usuario debe verlas todas; Combobox editable si el valor puede estar fuera del enum; MultiSelect si se aceptan varios.

Medición propuesta

Eventos planificados

select.open

Herramienta
OTLP · Events
Cobertura
Cada apertura del menú

Atributos: options count, searchable, origin. Detecta Selects con menú abierto varias veces sin selección (fricción).

select.search_used

Herramienta
OTLP · Metrics
Cobertura
Ratio de búsqueda dentro del combobox

Si el ratio supera 60%, el umbral de promoción a searchable podría bajarse de 12 a 8 opciones.

Mutación plástica (Estado 3)

Qué muta y qué permanece

Reordenación contextual options-order = derive(historial-local)

Las opciones más usadas por el lector suben al principio, sin ocultar ninguna. El orden del enum canónico se mantiene como fuente; la presentación se reordena localmente.

Apertura del menú direction = derive(posición-viewport)

Floating UI decide si abre hacia arriba o hacia abajo según espacio disponible. Agnóstico al lector.

Búsqueda activable searchable = derive(options.length × locale)

El umbral 12 opciones baja en idiomas donde cada opción es más larga (alemán).

Fijo por contract schema enum · aria-expanded · aria-activedescendant · Escape para cerrar

Nunca mutan. El patrón WAI-ARIA combobox es inviolable.

Rollback automático si la reordenación propone ocultar una opción o si el searchable se desactiva cuando debería estar activo (más de 12 opciones visibles). El lector nunca pierde visibilidad del rango completo.

Genealogía

Árbol de evolución

<select> nativo

Sin componente. Estilizado con CSS dentro de los límites del control nativo.

Consumidor Diseñador y desarrollador

Componente React custom

Reescrito como <Select /> con menú custom para soportar búsqueda. Rompió accesibilidad en mobile.

Consumidor Producto · 6 productos

Política native-first

Marcha atrás. Se vuelve a <select> nativo por defecto. El custom queda como variant promovida bajo umbral.

Consumidor Producto · 22 productos

Select.AI · expuesto vía MCP

Enum publicado vía MCP. Agente tier-2 puede componer formularios con Select cerrado.

Consumidor Humano + agente tier-1 + agente tier-2

Select plástico

planificado

Reordenación contextual del listado según historia local del usuario. Sin ocultar opciones; solo reordenando lo más usado al principio.

Consumidor Estado 3

Notas del editor

Descartes catalogados

Variants rechazadas

variant='cascading'

Selects encadenados (país → región → ciudad) generaban estados intermedios difíciles de validar y de explicar a un agente. Sustituido por componente <CascadingSelect /> separado con su propio contrato.

variant='editable'

Combobox que permite escribir valores fuera del enum. Conflicto con la regla de cierre estricto del schema. Movido a un componente <Combobox editable=true /> distinto.

Referencias cruzadas