Um checklist aninhado para escolher o componente certo quando vários parecem "próximos o suficiente". Use isso antes de recorrer a shadcn/ui, MUI, Headless UI, React Native Paper ou Tamagui - o primitivo errado trava fricção que nenhum estilo pode corrigir depois.
O que o usuário está realmente fazendo? (selecionando, navegando, revelando, confirmando, inserindo, monitorando)
Quantas opções / estados / etapas estão envolvidas? (1, 2, 3–5, 6–15, 16+, ilimitado)
A escolha é mutuamente exclusiva ou multi-seleção?
O resultado é reversível ou destrutivo? (destrutivo exige mais fricção)
Qual é a superfície principal - desktop, web mobile, iOS nativo, Android nativo, ou todos os quatro?
Qual é a modalidade de entrada? (mouse, toque, apenas teclado, leitor de tela, voz, caneta)
O componente está no caminho crítico (checkout, cadastro) ou é ambiente (configurações, filtros)?
As opções são conhecidas no momento da compilação, buscadas uma vez, ou transmitidas/paginadas?
O usuário precisa comparar opções lado a lado, ou escanear sequencialmente?
Se você não conseguir responder a essas perguntas em uma frase cada, pare e esclareça com o solicitante. As decisões de componentes abaixo são consequência desse enquadramento.
2 opções que cabem em uma linha? → Controle segmentado / Grupo de Alternância (amigável para mobile, instantâneo, sem estado oculto). Web: ToggleGroup. Nativo: controle segmentado / SegmentedButtons (Paper).
2–5 opções, todas importantes para ver de uma vez? → Grupo de rádio. Melhor para formulários onde a própria escolha é informativa (velocidade de envio, nível do plano).
6–15 opções? → Select / Dropdown. Em mobile, prefira o <select> nativo na web e o seletor nativo (Picker / ActionSheetIOS / BottomSheet) no React Native - eles obtêm a UI de roda/sheet do nível do SO gratuitamente.
16+ opções ou buscadas dinamicamente? → Combobox / Autocompletar com digitação para filtrar. Necessário quando a rolagem se torna dolorosa.
Opções hierárquicas ou agrupadas (país → estado)? → Select em cascata ou Combobox com seções agrupadas, não rádios aninhados.
Opções visuais (cores, avatares, templates)? → Cartões de rádio ou grupo de chips, não um dropdown de texto.
Armadilha mobile: um dropdown personalizado que funcionou lindamente no desktop geralmente parece quebrado em um telefone (alvo de toque pequeno, sem rolagem de momentum, sem haptics). Prefira seletores nativos em superfícies de toque, a menos que você tenha um motivo forte.
Estes três não são intercambiáveis. Escolha por quando a mudança entra em vigor e que tipo de valor representa.
Configuração que entra em vigor imediatamente, sem necessidade de submissão? → Switch (ex: "Modo escuro", "Notificações"). Em nativo, use o Switch da plataforma - iOS e Android o renderizam de forma diferente e os usuários esperam isso.
Uma das muitas opções em um formulário, aplicada na submissão? → Checkbox (ex: "Eu concordo com os termos", "Inscrever-se na newsletter").
Uma ação que muda o estado da visualização, como negrito/itálico em um editor? → Botão de alternância (botão de ícone com aria-pressed).
Uma ação verdadeiramente transitória que faz algo agora e não é um estado? → Botão, não uma alternância.
Acessibilidade: switches precisam de role="switch" (web) e o accessibilityRole correto (switch, nativo). Uma checkbox estilizada como um switch falha com leitores de tela.
Todos os quatro escondem conteúdo até ser solicitado. Diferem em quantos painéis podem estar abertos e se os itens são pares.
Muitos itens pares independentes, qualquer número pode estar aberto ao mesmo tempo (FAQ)? → Acordeão (modo multi-abertura).
Muitos itens pares, apenas um aberto por vez (especificações / envio / avaliações)? → Acordeão (modo de abertura única) ou Abas - escolha Abas se os painéis forem aproximadamente iguais em importância e comprimento, Acordeão se forem prosa longa.
Uma única região de mostrar/esconder - "Mostrar mais", configurações avançadas? → Colapsível (uma revelação, sem grupo).
Expansão inline minúscula, com sensação nativa, sem necessidade de estado JS? → <details> / <summary> na web. Nativo do navegador, a11y gratuito, SEO gratuito, descoberta Ctrl+F gratuita.
Contexto mobile, painéis são de largura total e o conteúdo é pesado? → Acordeão (Abas ficam apertadas abaixo de ~360px).
Contexto mobile, o conteúdo é curto e a comparação lado a lado ajuda? → Abas com rolagem horizontal para overflow.
Anti-padrão: abas com 7+ itens em mobile. Ou mude para um seletor / segmentado rolável, ou repense a IA.
Escolha por roubo de foco, dismissibilidade e tamanho do conteúdo.
Bloqueia a tarefa inteira até ser tratada, pode ter um formulário? → Modal / Diálogo. Prende o foco, retorna o foco ao fechar.
Painel lateral de conteúdo relacionado, página abaixo permanece significativa? → Drawer / Sheet. Em mobile, prefira bottom sheet (alcançável pelo polegar); em desktop, side drawer.
Menu contextual pequeno ou informação ancorada a um gatilho? → Popover.
Linha única, apenas hover, rótulo suplementar? → Tooltip. ⚠️ Tooltips não existem em dispositivos de toque - nunca coloque informações críticas lá. Usuários de mobile sentirão falta disso.
Confirmar uma ação destrutiva? → Diálogo de alerta (um modal mais restrito com confirmação/cancelamento explícito).
Feedback por tempo limitado após uma ação ("Salvo")? → Toast / Snackbar. Não coloque ações necessárias em um toast - ele se auto-descarta.
Status persistente na página que o usuário deve reconhecer? → Alerta / Banner (permanece até ser dispensado ou corrigido).
Regra geral mobile: se você usaria um popover ou tooltip no desktop, use um bottom sheet no mobile. Overlays ancorados se comportam mal quando o teclado abre.
Itens que o usuário está navegando (produtos, fotos, recomendações)? → Carrossel horizontal (pares com swipe de polegar no mobile, arrasto de mouse no desktop).
Itens que o usuário está consumindo sequencialmente (stories, reels, feed)? → Carrossel vertical / paginador vertical (modelo TikTok / Stories). Certo quando cada item é tela cheia e imersivo.
Ambos os eixos parecem plausíveis (uma galeria)? → Horizontal, exceto em telas de TV / paisagem grandes onde vertical é lido como uma lista e horizontal como destacado.
Mais de ~10 itens? → Não use carrossel - mude para um rail rolável (sem avanço automático, sem pontos de paginação), uma grade, ou paginação.
Carrossel principal / promocional? → Considere fortemente não construir um. Carrosséis principais com avanço automático têm quedas de engajamento bem documentadas; um herói estático ou dois cards empilhados geralmente superam.
Usuário precisa de link profundo e previsibilidade do botão voltar (resultados de busca)? → Paginação.
Feed mobile onde o engajamento importa mais que a navegação? → Scroll infinito, mas com um rodapé que ainda é alcançável (use um botão "Carregar mais" no final do primeiro lote prático, ou exponha um rodapé em um drawer).
Usuário precisa saber quanto resta? → Botão carregar mais com uma contagem, não infinito.
Formulário / assistente multi-etapas? → Stepper, com um indicador de progresso visível.
Valor impreciso onde a sensação importa (volume, brilho)? → Slider.
Valor preciso que o usuário conhece (idade, quantidade)? → Entrada numérica com inputMode="numeric" no mobile.
Pequeno intervalo de inteiros, ações ±1 parecem naturais (quantidade do carrinho)? → Stepper / NumberInput com botões ±. Alvos de toque amigáveis são essenciais aqui (mínimo de 44pt).
Intervalo com dois pontos finais (preço mínimo – preço máximo)? → Slider de intervalo.
3–5 baldes discretos? → Controle segmentado ("P / M / G / GG"), não um slider.
Data ou hora? → Seletor nativo no mobile (<input type="date"> web, DatePickerIOS / DatePickerAndroid / seletor de data da comunidade no RN). Calendários personalizados só são corretos quando o intervalo, multi-seleção ou regras de negócios o exigem.
Se você passou pelo checklist e duas opções ainda parecem igualmente válidas, use estes padrões - eles são a escolha de menor risco na maioria das vezes:
Seleção de tamanho desconhecido → Combobox.
Alternância em uma tela de configurações → Switch.
Alternância em um formulário enviado posteriormente → Checkbox.
Um de três modos de visualização → Controle segmentado.
Confirmar uma ação destrutiva → Diálogo de alerta com o botão destrutivo estilizado em vermelho e rotulado com o verbo ("Excluir conta"), não "OK".
Overlay mobile → Bottom sheet.
Dropdown de seleção única mobile → Seletor nativo.
Lista de 50+ itens → Lista virtualizada (react-window web, FlatList / FlashList nativo), nunca um .map() simples.