# Como escolher componentes Vue e Nuxt para vibe coding

Por Thales Andrades Machado · Atualizado em 23 de outubro de 2026

> Antes de colar um componente no projeto, confira quatro pontos: quanto ele pesa no carregamento (Core Web Vitals), se funciona pelo teclado e respeita prefers-reduced-motion, se a licença permite uso comercial e se roda no Nuxt com SSR sem erro de hidratação. No THM Componentes, a ficha técnica de cada componente mostra peso, tecnologia e movimento reduzido.

Em vibe coding, a IA escreve o código do componente que você pedir, mas não decide sozinha se ele cabe no seu projeto. Os problemas aparecem depois: a página demora a abrir no celular, um efeito não para de se mexer, o build do Nuxt quebra com "window is not defined" ou o componente vem de um repositório cuja licença você nunca leu. Quatro verificações, feitas antes de colar o código, cobrem esses casos.

A resposta curta: escolha componentes que pesem pouco no carregamento ou que carreguem sob demanda, que funcionem sem mouse e com movimento reduzido, que tenham licença compatível com o seu uso e que rodem no Nuxt com renderização no servidor (SSR). A tabela resume o que olhar em cada ponto.

| Critério | O que verificar | Sinal de alerta |
|---|---|---|
| Peso no carregamento | LCP, INP e CLS antes e depois; se o componente carrega sob demanda | WebGL ou simulação no topo da página, carregados junto com o resto |
| Acessibilidade | Teclado, foco visível, prefers-reduced-motion e contraste | Animação contínua sem pausa; ações que só funcionam com mouse |
| Licença | MIT ou termos que permitam uso comercial; aviso de copyright mantido | Código sem licença declarada ou com uso comercial proibido |
| Nuxt e SSR | Acesso a window e document só no navegador; nenhum aviso de hidratação | Erro "window is not defined" no build ou hydration mismatch no console |

## Quanto um componente pode pesar sem prejudicar o Core Web Vitals?

O Core Web Vitals reúne três métricas da experiência de carregamento. O LCP (Largest Contentful Paint) mede quando o maior elemento visível aparece e deve ficar em até 2,5 segundos. O INP (Interaction to Next Paint) mede a resposta a cliques e toques e deve ficar em até 200 milissegundos. O CLS (Cumulative Layout Shift) mede quanto o layout pula durante o carregamento e deve ficar em até 0,1. O web.dev recomenda avaliar as três no percentil 75 dos carregamentos, separando celular e computador.

Um componente visual afeta cada métrica de um jeito:

- **LCP**: um efeito em WebGL no topo da página baixa código e ocupa o processador justamente enquanto o título e a imagem principal estão carregando.
- **INP**: animações que rodam JavaScript o tempo todo ocupam a thread principal, e o clique da pessoa demora a ter resposta.
- **CLS**: componentes que só ganham altura depois de carregar empurram o texto para baixo. Reserve o espaço com altura fixa ou proporção definida.

No THM Componentes, a ficha técnica de cada componente traz a linha **Peso no carregamento**, com quatro níveis: Leve (CSS ou JavaScript leve, sem custo perceptível), Médio (canvas ou animação contínua, bom para uma seção), Pesado (WebGL ou simulação, um por página e carregado sob demanda) e Experimental (usa uma API de navegador ainda em teste, com alternativa automática quando ela não existe). Dos 268 componentes do catálogo, 60 usam WebGL. Para comparar: [Névoa](https://vibecode.thmtecnologia.com/componentes/nevoa/) usa só CSS e fica no nível Leve; [Nanquim](https://vibecode.thmtecnologia.com/componentes/nanquim/) simula um fluido na placa de vídeo com WebGL2 e fica no nível Pesado.

A regra prática é um efeito pesado por página, fora do caminho do LCP. No Nuxt, dois recursos ajudam. O prefixo `Lazy` no nome do componente adia o carregamento do código dele, o que reduz o pacote inicial. A hidratação adiada controla quando o componente fica interativo: `hydrate-on-visible` hidrata quando ele entra na tela, `hydrate-on-idle` quando o navegador está ocioso e `hydrate-on-interaction` depois de uma interação, como um clique. Um globo como [Meridiano](https://vibecode.thmtecnologia.com/componentes/meridiano/), quando fica no meio da página, é o caso típico para os dois.

```text
Coloque o globo 3D da seção de mapa com o prefixo Lazy do Nuxt e hydrate-on-visible, para ele carregar só quando entrar na tela. Reserve a altura do bloco para não causar mudança de layout, mostre uma imagem estática enquanto o WebGL não está pronto e compare o LCP e o INP da página antes e depois.
```

Antes de aceitar a versão final, meça a página com e sem o componente, no celular, e compare os três números. Se o LCP passar de 2,5 segundos por causa do efeito, troque por uma versão mais leve ou mova o efeito para mais abaixo na página.

## Como saber se o componente é acessível?

Acessibilidade em componentes visuais começa pelo movimento. A media query `prefers-reduced-motion` detecta quando a pessoa ativou, no aparelho, a opção de reduzir movimentos não essenciais; o valor `reduce` indica que a opção está ligada. Segundo o MDN, animações que ampliam ou deslocam objetos grandes podem causar desconforto em quem tem distúrbios vestibulares. Windows, macOS, iOS e Android têm essa opção nas configurações de acessibilidade.

Dois critérios da WCAG 2.2, a diretriz de acessibilidade do W3C, tratam de movimento:

- **2.2.2 Pause, Stop, Hide (nível A)**: conteúdo que se move sozinho, dura mais de cinco segundos e aparece junto com outro conteúdo precisa de um jeito de pausar, parar ou ocultar, a menos que o movimento seja essencial.
- **2.3.3 Animation from Interactions (nível AAA)**: a animação de movimento disparada por uma interação pode ser desligada, a menos que seja essencial para a função ou para a informação.

Além do movimento, confira o básico da interação: toda função precisa funcionar pelo teclado (critério 2.1.1, nível A), o indicador de foco do teclado precisa ficar visível (2.4.7, nível AA) e o texto precisa de contraste de pelo menos 4,5:1 com o fundo (1.4.3, nível AA).

Um teste de cinco minutos mostra o essencial:

1. Deixe o mouse de lado e percorra o componente com Tab, Shift+Tab, Enter, Espaço, setas e Esc. Tudo que funciona com clique precisa funcionar assim, e você precisa ver onde está o foco.
2. Ative a redução de movimento no sistema e recarregue a página. O componente deve parar, congelar ou trocar a animação por um estado estático.
3. Observe por dez segundos. Se algo se mexe sozinho sem parar, precisa de um botão de pausa ou de uma versão estática.
4. Leia os textos que ficam sobre o efeito. Se o contraste cair em algum momento da animação, ajuste as cores ou acrescente um fundo atrás do texto.

Na ficha técnica do THM Componentes, a linha **Movimento reduzido** diz se o componente respeita `prefers-reduced-motion` no próprio código ou se o prompt pede à IA uma versão estática. Em interfaces de aplicação, procure componentes pensados para o teclado desde o início: [Trevo](https://vibecode.thmtecnologia.com/componentes/trevo/) abre num `dialog` nativo, com busca e atalhos; [Esteira](https://vibecode.thmtecnologia.com/componentes/esteira/) permite arrastar cartões só pelo teclado; e [Anilina](https://vibecode.thmtecnologia.com/componentes/anilina/) traz verificação de contraste WCAG para quem está definindo a paleta.

```text
Revise a acessibilidade deste componente. Tudo precisa funcionar com Tab, Enter, Espaço, setas e Esc, com foco visível. Com prefers-reduced-motion ativo, troque a animação por um estado estático. Se houver movimento automático por mais de cinco segundos, inclua um botão de pausa. Confira contraste mínimo de 4,5:1 nos textos e me mostre o que mudou.
```

## Qual licença permite usar um componente em projeto comercial?

Quando o componente vem de código aberto, a licença diz o que você pode fazer com ele. A licença MIT, por exemplo, dá permissão gratuita para usar, copiar, modificar, mesclar, publicar, distribuir, sublicenciar e vender cópias do software, o que inclui projetos comerciais e de clientes. A condição é incluir o aviso de copyright e o texto da permissão em todas as cópias ou partes substanciais do código. O software vem "como está", sem garantia de nenhum tipo.

Na prática, três cuidados evitam dor de cabeça:

- **Mantenha o aviso.** Ao reescrever um arquivo, a IA pode apagar os comentários do topo, inclusive o de copyright. Peça de forma explícita para manter o aviso no arquivo ou num `LICENSE` dentro da pasta do componente.
- **Sem licença declarada, não presuma liberdade.** Código publicado sem licença não traz a permissão que a MIT concede. Na dúvida, pergunte ao autor ou escolha outro componente.
- **Catálogos pagos têm termos próprios.** Leia o que é permitido: uso em projetos de clientes, número de projetos, revenda e redistribuição.

No THM Componentes, a linha **Origem** da ficha técnica informa se o componente é exclusivo da THM ou adaptado de código aberto sob licença MIT. As condições de uso comercial do catálogo estão nas [perguntas frequentes](https://vibecode.thmtecnologia.com/perguntas/) e nos [termos de uso](https://thmtecnologia.com/termos/).

```text
Este componente é de código aberto sob licença MIT. Ao adaptar para o meu projeto, mantenha o aviso de copyright e o texto da licença num arquivo LICENSE dentro da pasta do componente e não apague comentários de autoria durante a refatoração.
```

## O componente funciona no Nuxt com SSR?

O Nuxt usa renderização universal por padrão: o servidor executa o código Vue e devolve a página pronta em HTML, e depois o navegador executa o mesmo código para ativar a interatividade, etapa chamada hidratação. O problema é que o servidor não tem `window`, `document`, `localStorage`, canvas nem WebGL. Um componente que acessa essas APIs durante a renderização quebra no servidor ou gera um HTML diferente do que o navegador espera, o que a documentação do Nuxt chama de hydration mismatch.

Sinais de um componente pronto para SSR:

- Todo acesso a `window`, `document`, canvas e WebGL acontece dentro de `onMounted`, que roda no navegador depois da hidratação.
- A renderização inicial não depende de valores aleatórios nem da hora atual, que mudam entre o servidor e o navegador.
- Listeners, timers e laços de animação são removidos quando o componente é desmontado.

Quando o componente só faz sentido no navegador, como um efeito em WebGL, o Nuxt oferece dois caminhos. O sufixo `.client` no nome do arquivo faz o componente ser renderizado só no cliente. O componente `<ClientOnly>` envolve o trecho e aceita um conteúdo de reserva, o slot `#fallback`, que o servidor renderiza e que aparece até o componente montar no navegador. Use essa reserva para ocupar o espaço do efeito e evitar CLS.

Confira também o estilo. Componentes escritos com Tailwind CSS v4 pedem o plugin `@tailwindcss/vite` no `nuxt.config.ts` e um arquivo CSS com `@import "tailwindcss"`, como mostra o guia oficial de instalação para Nuxt. O THM Componentes é escrito para Vue 3, Nuxt, TypeScript e Tailwind CSS v4, e a linha **Tecnologia** da ficha técnica lista o que cada componente usa.

```text
Adapte este componente para o Nuxt com SSR. Mova todo acesso a window, document, canvas e WebGL para onMounted, remova listeners e requestAnimationFrame em onBeforeUnmount e tire valores aleatórios ou de data da renderização inicial. Se ele só funcionar no navegador, envolva com ClientOnly e use o fallback para reservar a altura. Rode o build e confirme que não aparece aviso de hydration mismatch no console.
```

## Como decidir entre dois componentes parecidos?

Quando dois componentes resolvem o mesmo problema, decida pela posição na página e pelo público:

- **No topo de uma página de vendas**, prefira Leve ou Médio. Use um Pesado, como [Nanquim](https://vibecode.thmtecnologia.com/componentes/nanquim/), só quando o efeito é a própria mensagem, como na abertura de um lançamento ou num portfólio, e carregue sob demanda.
- **Em telas de aplicação**, como painéis e formulários, priorize teclado, leitores de tela e resposta rápida ao clique. Um formulário bem resolvido, como [Despachante](https://vibecode.thmtecnologia.com/componentes/despachante/), com máscaras e validação de CPF, CNPJ e CEP, importa mais nessas telas do que um fundo animado.
- **Para um público que usa celulares antigos**, troque efeitos contínuos por versões estáticas ou por animações simples em CSS.

Antes de dar a escolha por encerrada, passe pela lista:

1. O peso combina com a posição na página, e efeitos pesados carregam sob demanda.
2. Tudo funciona pelo teclado, com foco visível.
3. Existe uma versão estática para `prefers-reduced-motion`.
4. A licença permite o seu uso, e o aviso de copyright continua no código.
5. O build do Nuxt passa sem erro, e o console não mostra aviso de hidratação.
6. LCP, INP e CLS continuam dentro das metas no celular.

Feita a escolha, peça à IA para aplicar o componente com as cores e a tipografia do seu projeto e para mostrar onde ele foi usado. Revisar esses quatro pontos antes de colar o código custa menos do que refazer a tela depois.

## Fontes

- [Web Vitals, web.dev](https://web.dev/articles/vitals)
- [prefers-reduced-motion, MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion)
- [Web Content Accessibility Guidelines (WCAG) 2.2, W3C](https://www.w3.org/TR/2023/REC-WCAG22-20231005/)
- [Understanding SC 2.2.2 Pause, Stop, Hide, W3C](https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide)
- [Understanding SC 2.3.3 Animation from Interactions, W3C](https://www.w3.org/WAI/WCAG22/Understanding/animation-from-interactions)
- [The MIT License, Open Source Initiative](https://opensource.org/license/mit)
- [Rendering Modes, documentação do Nuxt](https://nuxt.com/docs/4.x/guide/concepts/rendering)
- [Components, documentação do Nuxt](https://nuxt.com/docs/directory-structure/app/components)
- [Nuxt and Hydration, documentação do Nuxt](https://nuxt.com/docs/guide/best-practices/hydration)
- [ClientOnly, documentação do Nuxt](https://nuxt.com/docs/api/components)
- [Install Tailwind CSS with Nuxt, Tailwind CSS](https://tailwindcss.com/docs/installation/framework-guides/nuxt)
