Flujo de decisión de componentes
Una lista de verificación anidada para elegir el componente correcto cuando varios parecen "lo suficientemente cerca". Úsalo antes de recurrir a shadcn/ui, MUI, Headless UI, React Native Paper o Tamagui — el primitivo equivocado bloquea la fricción que ningún estilo puede solucionar después.
Esta guía trata React web y React Native / web móvil como ciudadanos de primera clase. Donde divergen, la recomendación lo llama explícitamente.
Paso 1 — Encuadra la decisión antes de explorar bibliotecas de componentes
- ¿Qué está haciendo realmente el usuario? (seleccionar, navegar, revelar, confirmar, introducir, monitorear)
- ¿Cuántas opciones / estados / pasos hay involucrados? (1, 2, 3–5, 6–15, 16+, ilimitado)
- ¿Es la opción mutuamente exclusiva o multi-selección?
- ¿Es el resultado reversible o destructivo? (destructivo necesita más fricción)
- ¿Cuál es la superficie principal — escritorio, web móvil, iOS nativo, Android nativo, o los cuatro?
- ¿Cuál es la modalidad de entrada? (ratón, táctil, solo teclado, lector de pantalla, voz, stylus)
- ¿El componente está en la ruta crítica (checkout, signup) o ambiental (configuración, filtros)?
- ¿Las opciones se conocen en tiempo de compilación, se obtienen una vez o se transmiten/pagina?
- ¿El usuario necesita comparar opciones lado a lado o escanearlas secuencialmente?
Si no puedes responder estas en una oración cada una, detente y aclara con el solicitante. Las decisiones de componentes a continuación dependen de este encuadre.
Paso 2 — Elige la familia
Empareja la intención del usuario con una familia, luego profundiza en el componente específico en el Paso 3.
- Selección — usuario elige 1+ de un conjunto conocido → Paso 3A
- Estado binario — usuario alterna encendido/apagado → Paso 3B
- Divulgación — usuario revela/oculta contenido en su lugar → Paso 3C
- Superposición / transitoria — contenido flota sobre la página → Paso 3D
- Navegación — usuario se mueve entre vistas → Paso 3E
- Contenido secuencial — usuario pagina a través de una serie → Paso 3F
- Entrada numérica / de rango → Paso 3G
- Notificación / estado → Paso 3H
Paso 3A — Selección: radio, checkbox, select, combobox, segmented, chips
La familia más ambigua. Decide por conteo, exclusividad y espacio en pantalla.
Selección única (mutuamente exclusiva)
- ¿2 opciones que caben en una línea? → Control segmentado / Toggle Group (móvil-amigable, instantáneo, sin estado oculto). Web:
ToggleGroup. Nativo: control segmentado /SegmentedButtons(Paper). - ¿2–5 opciones, todas importantes de ver a la vez? → Grupo de radio. Mejor para formularios donde la opción en sí es informativa (velocidad de envío, nivel de plan).
- ¿6–15 opciones? → Select / Dropdown. En móvil, prefiere el
<select>nativo en web y el picker nativo (Picker/ActionSheetIOS/BottomSheet) en React Native — obtienen la interfaz de rueda/hoja del nivel del SO de forma gratuita. - ¿16+ opciones u obtenidas dinámicamente? → Combobox / Autocomplete con tipo para filtrar. Requerido una vez que el desplazamiento se vuelve doloroso.
- ¿Opciones jerárquicas o agrupadas (país → estado)? → Select en cascada o Combobox con secciones agrupadas, no radios anidados.
- ¿Opciones visuales (colores, avatares, plantillas)? → Tarjetas de radio o grupo de chips, no un dropdown de texto.
Gotcha móvil: un dropdown personalizado que se vea hermoso en escritorio generalmente se siente roto en un teléfono (pequeño objetivo de golpe, sin scroll de momento, sin hápticos). Por defecto, usa selectores nativos en superficies táctiles a menos que tengas una razón fuerte.
Selección múltiple
- ¿2–7 opciones, todas visibles? → Grupo de checkbox.
- ¿8+ opciones o filtrables? → Combobox multi-select con chips para valores seleccionados.
- ¿Etiqueta / estilo de categoría con entrada de texto libre? → Tag input / chip input.
- ¿Mutuamente exclusivo dentro de categorías (filtros facetados)? → Panel de filtro facetado (grupos de checkbox dentro de acordeones o popovers).
Paso 3B — Estado binario: switch, checkbox, toggle button
Estos tres no son intercambiables. Elige por cuándo toma efecto el cambio y qué tipo de valor representa.
- ¿Configuración que toma efecto inmediatamente, no se necesita envío? → Switch (p. ej. "Modo oscuro", "Notificaciones"). En nativo, usa la
Switchde la plataforma — iOS y Android lo renderizan diferente y los usuarios esperan eso. - ¿Uno de muchas opciones en un formulario, aplicado al enviar? → Checkbox (p. ej. "Acepto los términos", "Suscribirse a boletín").
- ¿Una pulsación que cambia el estado de la vista, como negrita/cursiva en un editor? → Toggle button (botón de icono con
aria-pressed). - ¿Una acción verdaderamente transitoria que hace algo ahora y no es un estado? → Button, no un toggle.
Accesibilidad: los switches necesitan
role="switch"(web) y el correctoaccessibilityRole(switch, nativo). Un checkbox estilizado como switch falla a los lectores de pantalla.
Paso 3C — Divulgación: accordion vs collapsible vs tabs vs details
Los cuatro ocultan contenido hasta solicitado. Difieren en cuántos paneles pueden estar abiertos y si los elementos son pares.
- ¿Muchos elementos pares independientes, cualquier número puede estar abierto a la vez (FAQ)? → Accordion (modo multi-abierto).
- ¿Muchos elementos pares, solo uno abierto a la vez (especificaciones / envío / reseñas)? → Accordion (modo de un solo abierto) o Tabs — elige Tabs si los paneles tienen importancia y longitud aproximadamente iguales, Accordion si son prosa larga.
- ¿Una única región de mostrar/ocultar — "Mostrar más", configuración avanzada? → Collapsible (una divulgación, sin grupo).
- ¿Expansión pequeña en línea, se siente nativa, no se necesita estado JS? →
<details>/<summary>en web. Nativo del navegador, accesibilidad gratis, SEO gratis, descubribilidad Ctrl+F gratis. - ¿Contexto móvil, los paneles tienen ancho completo y el contenido es pesado? → Accordion (Tabs se vuelven abarrotados bajo ~360px).
- ¿Contexto móvil, el contenido es corto y la comparación lado a lado ayuda? → Tabs con scroll horizontal para desbordamiento.
Anti-patrón: tabs con 7+ elementos en móvil. Ya sea cambia a un select / scroll segmentado, o replantea la IA.
Paso 3D — Superposiciones: modal vs drawer vs popover vs tooltip vs toast
Elige por robo de enfoque, descartalidad y tamaño del contenido.
- ¿Bloquea la tarea completa hasta ser manejada, puede tener un formulario? → Modal / Dialog. Atrapa el enfoque, devuelve el enfoque al cerrar.
- ¿Panel lateral de contenido relacionado, página debajo permanece significativa? → Drawer / Sheet. En móvil, prefiere hoja inferior (alcance del pulgar); en escritorio, drawer lateral.
- ¿Menú contextual pequeño o información anclada a un trigger? → Popover.
- ¿Una línea, solo hover, etiqueta complementaria? → Tooltip. ⚠️ Los tooltips no existen en táctil — nunca pongas información crítica ahí. Los usuarios móviles la perderán.
- ¿Confirmando una acción destructiva? → Alert dialog (un modal más restringido con confirmar/cancelar explícito).
- ¿Retroalimentación limitada en tiempo después de una acción ("Guardado")? → Toast / Snackbar. No pongas acciones requeridas en un toast — se descarta automáticamente.
- ¿Estado persistente en página que el usuario debe reconocer? → Alert / Banner (permanece hasta ser descartado o fijado).
Regla práctica móvil: si recurrirías a un popover o tooltip en escritorio, recurre a una hoja inferior en móvil. Las superposiciones ancladas se portan mal cuando se abre el teclado.
Paso 3E — Navegación: tabs vs sidebar vs segmented vs breadcrumb vs bottom nav
- ¿2–5 vistas pares dentro de una página? → Tabs.
- ¿5–15 destinos en toda la app, primero escritorio? → Navegación de barra lateral.
- ¿3–5 destinos de nivel superior en móvil? → Barra de pestañas inferior (patrón nativo en iOS/Android; en web móvil, navegación inferior fija).
- ¿Mostrando profundidad / ubicación en una jerarquía? → Breadcrumb.
- ¿2–4 modos de vista (lista / grid / mapa)? → Control segmentado en el encabezado, no tabs.
- ¿Muchos destinos con desbordamiento? → Sidebar con secciones plegables (web) o drawer activado por hamburguesa (móvil).
Paso 3F — Contenido secuencial / paginado: carousel, pagination, infinite scroll, stepper
Carousel horizontal vs vertical
- ¿Elementos que el usuario está navegando (productos, fotos, recomendaciones)? → Carousel horizontal (se empareja con swipe de pulgar en móvil, arrastre de ratón en escritorio).
- ¿Elementos que el usuario está consumiendo secuencialmente (historias, reels, feed)? → Carousel vertical / paginador vertical (modelo TikTok / Stories). Perfecto cuando cada elemento es a pantalla completa e inmersivo.
- ¿Ambos ejes se sienten plausibles (una galería)? → Horizontal, excepto en TV / pantallas grandes en landscape donde vertical se lee como una lista y horizontal se lee como destacado.
- ¿Más de ~10 elementos? → No carousel — cambia a un carril desplazable (sin auto-avance, sin puntos de paginación), una grid o pagination.
- ¿Carousel de héroe / promocional? → Considera fuertemente no construir uno. Los carousels de héroe de auto-avance tienen caídas de engagement bien documentadas; un héroe estático o dos tarjetas apiladas generalmente superan.
Pagination vs infinite scroll vs load-more
- ¿Usuario necesita linkabilidad profunda y previsibilidad de botón atrás (resultados de búsqueda)? → Pagination.
- ¿Feed móvil donde importa más el engagement que la navegación? → Infinite scroll, pero con un footer que sigue siendo alcanzable (usa un botón "Cargar más" al final del primer lote práctico, o expone un footer en un drawer).
- ¿Usuario necesita saber cuánto falta? → Botón load-more con un conteo, no infinito.
- ¿Formulario multi-paso / wizard? → Stepper, con un indicador de progreso visible.
Paso 3G — Entrada numérica & de rango: slider, stepper, input, segmented
- ¿Valor impreciso donde la sensación importa (volumen, brillo)? → Slider.
- ¿Valor preciso que el usuario sabe (edad, cantidad)? → Number input con
inputMode="numeric"en móvil. - ¿Rango de enteros pequeño, acciones ±1 se sienten naturales (cantidad del carrito)? → Stepper / NumberInput con botones ±. Los objetivos de golpe táctiles amigables son esenciales aquí (44pt mínimo).
- ¿Rango con dos endpoints (precio mín–precio máx)? → Range slider.
- ¿3–5 buckets discretos? → Control segmentado ("S / M / L / XL"), no un slider.
- ¿Fecha u hora? → Native picker en móvil (
<input type="date">web,DatePickerIOS/DatePickerAndroid/ date picker de comunidad en RN). Los calendarios personalizados son adecuados solo cuando el rango, multi-select o reglas de negocio lo requieren.
Paso 3H — Notificación / estado: toast, alert, banner, badge, skeleton
- ¿La acción se acaba de completar, sin reconocimiento necesario? → Toast (3–5s).
- ¿Mensaje del sistema persistente ("Estás offline")? → Banner en la parte superior.
- ¿Problema de campo/formulario en línea? → Alerta en línea debajo del campo.
- ¿Error o advertencia a nivel de página? → Componente Alert en la parte superior del área de contenido.
- ¿Indicador numérico o booleano en otro elemento ("3 sin leer")? → Badge.
- ¿Contenido de carga que el usuario está a punto de ver? → Skeleton que coincida con el diseño final (no un spinner) para ganancias de rendimiento percibido.
- ¿Trabajo indeterminado en segundo plano? → Spinner / indicador de progreso.
Paso 4 — Verificaciones transversales antes de confirmar
Ejecuta esta lista contra el componente que has elegido.
- ¿Objetivos táctiles ≥ 44pt (iOS) / 48dp (Android)? Especialmente para steppers, switches, botones de cerrar.
- ¿Navegable por teclado? El orden de tab tiene sentido, Enter/Space activan, Escape cierra superposiciones.
- ¿El lector de pantalla anuncia cambios de estado?
aria-expanded,aria-pressed,aria-selected,role="switch",aria-livepara toasts. - ¿Funciona sin JS / en redes lentas?
<select>nativo,<details>,<form>se degradan gracefully; los reemplazos personalizados frecuentemente no. - ¿Respeta
prefers-reduced-motion? Los carousels, acordeones, hojas deben saltar o acortar animación. - ¿Es seguro derecha-a-izquierda? Los carousels, breadcrumbs, sliders necesitan dirección consciente de RTL.
- ¿Usuarios solo teclado móvil (teclados Bluetooth en iPad)? Las mismas reglas de enfoque que escritorio.
- ¿Se aplicaron tokens de modo oscuro? No solo la superficie — bordes, anillos de enfoque, estados deshabilitados.
- ¿El componente se escala al contenido realista más largo? Las cadenas traducidas pueden ser 30–60% más largas.
- ¿El componente tiene un estado vacío sensato? Selects vacíos, listas vacías, sin resultados.
Paso 5 — Mapa rápido de paridad Web ↔ Móvil
Misma intención, primitivo diferente. Elige el nativo de la plataforma al enviar React Native, y el equivalente web más cercano al enviar web.
| Intención | Web (React) | React Native |
|---|---|---|
| Selección única, muchas opciones | <select> / Combobox | Picker / hoja de acción nativa / hoja inferior |
| Selección múltiple, muchas opciones | Multi-combobox + chips | Hoja inferior con lista de checkbox |
| Configuración encendido/apagado | Switch (shadcn / Radix) | Switch (RN core) |
| Divulgación rápida | <details> / Collapsible | Pressable + LayoutAnimation / Reanimated |
| Panel lateral / hoja | Drawer / Sheet | Hoja inferior (@gorhom/bottom-sheet) |
| Superposición en línea | Popover | Hoja inferior (los popovers se portan mal con teclado) |
| Tooltip | Tooltip (hover) | Saltar — usa texto de ayuda en línea o icono de info → hoja |
| Toast | Toast (sonner, Radix) | Snackbar (Paper) / banner nativo |
| Pagination | Control de paginación | Reemplaza con infinite scroll + pull-to-refresh |
| Tabs | Tabs (Radix / shadcn) | Top tabs (@react-navigation/material-top-tabs) |
| Bottom nav | Barra inferior fija opcional | @react-navigation/bottom-tabs |
| Carousel | Embla / Swiper | FlatList horizontal / react-native-reanimated-carousel |
| Date picker | <input type="date"> | @react-native-community/datetimepicker |
Paso 6 — Valores predeterminados cuando estés atascado
Si has pasado por la lista de verificación y dos opciones aún se sienten igualmente válidas, usa estos valores predeterminados — son la elección de menor riesgo la mayoría de las veces:
- Selección de tamaño desconocido → Combobox.
- Toggle en una pantalla de configuración → Switch.
- Toggle en un formulario enviado después → Checkbox.
- Uno-de-tres modos de vista → Control segmentado.
- Confirmar una acción destructiva → Alert dialog con el botón destructivo estilizado en rojo y etiquetado con el verbo ("Eliminar cuenta"), no "OK".
- Superposición móvil → Hoja inferior.
- Dropdown de selección única móvil → Native picker.
- Lista de 50+ elementos → Lista virtualizada (
react-windowweb,FlatList/FlashListnativo), nunca un.map()plano.
Referencias cruzadas
- Accordion, Tabs — decisiones de divulgación en Paso 3C
- Radio Group, Checkbox, Select, Dropdown, Toggle Group — Paso 3A
- Switch — Paso 3B
- Modal, Popover, Tooltip, Toast, Alert — Paso 3D
- Sidebar, Breadcrumb, Pagination — Paso 3E y 3F
- Slider — Paso 3G
- Badge, Skeleton — Paso 3H