O Radix Morreu, Use Isso no Lugar... (Base UI)

BBetter Stack
Computing/SoftwareInternet Technology

Transcript

00:00:00Pare de usar componentes Radix e mude para o quê? Bem, para o Base UI. Na verdade, se você é fã do shadcn,
00:00:06já existe a opção de migrar agora. Se você ainda não ouviu falar do Base UI, ele é,
00:00:10na verdade, dos criadores originais do Radix, Floating UI e Material UI. É uma biblioteca de UI headless,
00:00:15então ela traz a funcionalidade e acessibilidade dos componentes, mas o design fica por sua conta,
00:00:20o que é bem importante hoje em dia, já que as LLMs ainda não são ótimas lidando com casos de borda
00:00:24e necessidades de acessibilidade. Mas o que descrevi aqui é exatamente o que o Radix faz,
00:00:30então por que você precisa de um novo? Bem, vamos direto ao ponto e eu vou te mostrar as principais diferenças.
00:00:35Vou começar rapidinho mostrando a documentação do Base UI para que você veja todos os
00:00:44componentes. Aqui na esquerda, dá para ver que eles têm praticamente todos os que você
00:00:48precisaria na sua biblioteca de componentes, até alguns avançados como o Combo Box que temos aqui,
00:00:52que você não encontra no Radix. E você verá em todos eles um ótimo exemplo de como
00:00:57implementar e estilizar com algo como CSS Modules. Dá até para mudar para um exemplo
00:01:01com Tailwind se preferir. A documentação é muito boa, mas não estamos aqui para comparar
00:01:06documentações, então vamos direto para a primeira grande diferença e a que você
00:01:10provavelmente mais ouvirá falar: o Base UI é ativamente mantido e o Radix está em um
00:01:15estado zumbi. Digo, se olharmos os gráficos de contribuição no GitHub, veremos que o Base UI
00:01:20está crescendo cada vez mais, enquanto o Radix parece receber apenas um commit ocasional. Mas fica
00:01:25ainda mais claro quando olhamos os PRs e issues fechados no último mês. Veja,
00:01:29o Base UI fechou 58 issues e mesclou 154 pull requests, enquanto o Radix não fechou nem mesclou
00:01:36absolutamente nada. O resumo do que houve com o Radix é que a WorkOS comprou a empresa por trás dele
00:01:42e não investiu no projeto. Assim, a equipe do Radix saiu em peso, e chegamos a esse estado atual.
00:01:47O co-criador do Radix chegou a dizer que só usaria o Radix se fosse sua última opção e, sim, ele
00:01:53agora está trabalhando no Base UI. Então trata-se de garantir que seus apps e dependências sejam ativamente
00:01:58mantidos e não causem dor de cabeça no futuro se você encontrar um bug que nunca será
00:02:02corrigido. Melhor ainda, o Base UI foi feito para ser bem similar ao Radix, então a migração não deve ser
00:02:08tão ruim; mas isso não significa que eles não puderam incluir algumas melhorias.
00:02:13E uma das minhas melhorias favoritas é como eles lidaram com a prop "asChild" que existe no Radix.
00:02:17Se você nunca viu isso, o que tenho aqui é um Select do Radix. Se eu quisesse renderizar um componente customizado
00:02:22como meu gatilho do select, e apenas o envolvesse com o componente Select.Trigger, você veria que
00:02:27eu teria um componente wrapper e também o botão que diz "inscrever-se" — algo que você deveria clicar, aliás.
00:02:31Mas se eu quisesse que o próprio botão "inscrever-se" servisse como o gatilho do select,
00:02:36tudo o que preciso fazer no Radix é adicionar a prop "asChild" ao gatilho. Isso diz ao
00:02:41Radix para mesclar todas as props e funcionalidades do gatilho com o componente que
00:02:46definimos como filho. Dá para ver isso acontecendo porque este classname aqui está sendo
00:02:50mesclado ao botão, sobrescrevendo-o neste caso. Se eu simplesmente deletar essa prop e
00:02:55salvar, você verá que agora temos um botão, mas ele funciona como meu gatilho do select.
00:03:00Essa é uma funcionalidade bem útil, mas uma reclamação comum era que ela não era muito
00:03:04explícita. Admito que, às vezes, ao revisar código rapidamente, eu deixava passar
00:03:09essa prop e, consequentemente, não percebia a causa de um problema. Se mudarmos para ver como isso
00:03:13é feito no Base UI, você obtém exatamente a mesma funcionalidade. Tenho um botão aqui que
00:03:18serve como meu gatilho, mas se olhar o código, em vez de usar "asChild", o Base UI usa
00:03:24a render prop. Na render prop, você especifica o componente que deseja, bem, renderizar
00:03:29como seu gatilho do select. É uma mudança pequena, mas acho que torna muito mais
00:03:34explícito o que está acontecendo: ele está literalmente renderizando este componente. Você não precisa
00:03:39ficar procurando se ele está usando o componente filho ou buscando a prop "asChild". Como eu disse,
00:03:43é uma mudança pequena, mas muito boa na minha opinião. E esse nem é o poder total da
00:03:48render prop. Veja que, ao construir um Switch, podemos passar uma função para a
00:03:52render prop, o que nos permite acessar as props e o estado do componente que estamos
00:03:56construindo. Neste caso, o polegar do switch. Isso nos permite escolher qual componente
00:04:01queremos aplicar as props repassadas e também aplicar uma lógica de renderização
00:04:05ou estilização customizada baseada no estado do componente. Assim, no caso do
00:04:10polegar do switch, podemos saber se ele está marcado, alterado, desativado, preenchido e muito mais.
00:04:14Aqui, estamos apenas verificando se ele está marcado ou não e, dependendo disso,
00:04:18renderizamos um ícone diferente. Existe até um hook que permite criar essa render
00:04:22prop nos seus próprios componentes, mas já estamos entrando em tópicos avançados. Espero
00:04:27que veja que qualquer customização que desejar, você conseguirá fazer com o Base UI.
00:04:31Voltando ao meu componente de Select, a próxima diferença é que o Base UI permite que alguns
00:04:35componentes sejam baseados em dados. Podemos ver isso no Select: o que tenho agora
00:04:40é o código do Radix Select. Temos um array aqui com rótulo e valor e, para colocar
00:04:44os valores no select, a única coisa que precisamos fazer é mapear o array "apples"
00:04:49e renderizar um Select.Item no Radix, o que adicionará os valores desta forma.
00:04:54Se pularmos para como isso é feito no Base UI, verá que é incrivelmente similar. Ainda temos o meu
00:04:59array aqui em cima e aqui embaixo ainda estamos mapeando e renderizando
00:05:03um Select.Item, mas também o incluímos em outro lugar: no Select.Root.
00:05:08Passamos o array ali e isso causa um impacto sutil: o componente agora está
00:05:13ciente dos dados que vai renderizar antes mesmo da renderização. Isso significa que há uma
00:05:17performance um pouco melhor, especialmente em Server-Side Rendering (SSR). Uma coisa que acho
00:05:22que poderia ser melhorada nisso, no entanto, é que atualmente passo "apples" na prop "items",
00:05:26mas aqui embaixo também estou mapeando o array "apples", usando-o em dois lugares.
00:05:32O que eles deveriam fazer é o que o React Aria faz, que é outra biblioteca headless. Veja,
00:05:36temos nosso array de animais, passamos ele como "items" aqui e, então, para os
00:05:41filhos, usamos apenas uma função. Ela saberá todos os itens que foram
00:05:45passados no elemento pai, assim não usamos o array em dois lugares e o
00:05:50elemento pai serve como provedor de dados. Com certeza é algo que ainda pode melhorar
00:05:55um pouco. Voltando ao meu componente Select, quero mostrar outra diferença,
00:05:59mas esta é específica do componente Select, enquanto a render prop e a abordagem
00:06:03orientada a dados estão em quase todos os componentes. Esta é específica do Select:
00:06:08a possibilidade de ter um multi-select. Isso fazia uma falta enorme no Radix.
00:06:13No Base UI, tudo o que você precisa fazer é adicionar a prop "multiple" no Select.Root,
00:06:17pode ser true ou false, e seu select vira um multi-select. É fácil assim. E para
00:06:22ir além, o Base UI tem outros componentes que faltavam no Radix, como Combo
00:06:27Box e Auto Complete, fruto do benefício de ser mantido ativamente para responder
00:06:33aos pedidos dos usuários. Agora, há mais duas diferenças que quero mostrar entre Radix e Base UI.
00:06:38Vamos mudar para o componente Checkbox porque já estou um pouco enjoado
00:06:41daquele componente de Select. A primeira diferença que quero mostrar é sobre estilização.
00:06:45O Base UI oferece outra opção de estilização que acho muito legal. Como podem ver,
00:06:50atualmente estou usando Tailwind. Você pode usar abordagens tradicionais como CSS puro, CSS
00:06:55Modules e muito mais. Mas se você estiver usando Tailwind, uma das formas comuns
00:06:59de estilizar um componente assim é usando atributos de dados para o estado. Temos o "data-checked"
00:07:04aqui e, se estiver marcado, usamos "bg-primary". Veja que temos uma string de estilos
00:07:08bem longa no Tailwind, o que às vezes pode se tornar um problema. Então,
00:07:13uma das opções que o Base UI oferece para ajudar nisso é usar uma função
00:07:17como seu classname. Isso te dá acesso ao estado do componente. No caso deste
00:07:22checkbox, estou aplicando estilos baseados em se o estado é "checked" ou "disabled".
00:07:26Estou fazendo isso com uma condicional simples e acho que é uma forma mais agradável de bater
00:07:31o olho no código e ver exatamente de onde vêm os estilos de marcado e desativado,
00:07:35em vez de ter que escanear aquela linha única em busca dos atributos de dados. Acho
00:07:40que ajuda ainda mais se você estiver usando algo como Vanilla CSS. Também funciona muito
00:07:45bem com outra biblioteca que eu gosto muito chamada Tailwind Variants. Veja aqui,
00:07:49estou simplesmente passando o estado para a minha função de checkbox e, no meu variant
00:07:53de Tailwind, temos nossos estilos base, mas também temos as variantes. E veja que
00:07:58estou apenas dizendo: se marcado for true, aplique estes estilos; se desativado for true, estes aqui.
00:08:02Acho isso bem mais claro do que usar aqueles atributos de dados, mas é uma questão de opinião
00:08:06e do que você se sente confortável usando. É ótimo que o Base UI nos dê essas escolhas. Também
00:08:11devo dizer que usar uma função como classname foi algo que me conquistou primeiro no
00:08:14React Aria. Parece que temos o React Aria de um lado, com uma curva de aprendizado
00:08:19mais íngreme, e o Radix, que é bem simples. O Base UI parece ter encontrado o meio-termo,
00:08:23pegando o que gosto em ambos para criar a biblioteca headless definitiva. Essas foram todas as
00:08:28principais diferenças que eu queria abordar, mas ainda há muito mais. O Base UI tem
00:08:33ótimo suporte para React Hook Form e TanStack Form, suporte a animações para tornar o
00:08:38processo mais fácil, e até recursos como input scrubbing,
00:08:42diálogos aninhados e menus que abrem ao passar o mouse. Tenho certeza que, se tiver um pedido razoável,
00:08:47eles responderiam no GitHub, já que é mantido ativamente. Vale dizer, porém,
00:08:52que eu provavelmente não sairia migrando meu app de Radix para Base UI imediatamente, pois não
00:08:57acho que o Radix esteja quebrado. Mas se for começar um projeto novo, usaria o Base UI sem dúvida.
00:09:02E se eu precisasse de algo como um Combo Box ou Auto Complete, também consideraria migrar. Me diga
00:09:07o que você acha do Base UI nos comentários. Aproveite e se inscreva no canal e, como sempre,
00:09:11até o próximo vídeo!

Key Takeaway

O Base UI é apresentado como a evolução definitiva das bibliotecas de UI headless, superando o Radix através de manutenção ativa, componentes avançados e uma API mais moderna e explícita.

Highlights

O Base UI surge como o sucessor espiritual do Radix

Timeline

Introdução ao Base UI e Estado do Radix

O autor inicia o vídeo recomendando a transição do Radix para o Base UI, destacando que os criadores originais do Radix e Material UI estão por trás deste novo projeto. Ele explica que o Radix entrou em um estado de estagnação, carinhosamente chamado de "zumbi", após ser adquirido pela WorkOS e perder sua equipe principal. Enquanto o Base UI apresenta centenas de pull requests e issues resolvidos recentemente, o Radix não demonstra atividade significativa no GitHub. A documentação do Base UI é elogiada por ser completa e oferecer exemplos práticos com CSS Modules e Tailwind. Este cenário torna o Base UI uma escolha mais segura para garantir a longevidade e a correção de bugs em projetos de software.

A Transição de "asChild" para Render Props

Nesta seção, o palestrante detalha uma das mudanças arquiteturais mais importantes: a substituição da prop "asChild" por Render Props. Ele demonstra como o "asChild" no Radix podia ser confuso durante revisões de código por não ser visualmente explícito sobre qual componente estava sendo renderizado. No Base UI, a Render Prop permite que o desenvolvedor veja exatamente o componente alvo, além de oferecer acesso direto ao estado interno, como se um switch está marcado ou desativado. Essa abordagem facilita a lógica de renderização condicional, permitindo trocar ícones ou estilos dinamicamente com base no estado do componente. O autor ressalta que essa flexibilidade torna a biblioteca extremamente poderosa para customizações complexas de acessibilidade e design.

Componentes Baseados em Dados e Performance

O vídeo explora a nova abordagem orientada a dados do Base UI, focando especificamente no componente Select. Ao contrário do Radix, onde os itens são apenas mapeados no JSX, o Base UI permite passar o array de dados diretamente para o componente raiz (Select.Root). Isso informa ao componente quais dados serão renderizados antecipadamente, resultando em uma melhoria notável de performance, especialmente em cenários de renderização no lado do servidor (SSR). O autor faz uma crítica construtiva sugerindo que a API poderia evoluir para se assemelhar ao React Aria, evitando o mapeamento duplo do array. No entanto, ele reforça que a estrutura atual já é um avanço tecnológico em relação ao que o Radix oferece atualmente.

Multi-select e Componentes Avançados

Um dos grandes diferenciais discutidos é a inclusão nativa da funcionalidade de multi-select, que era uma das maiores ausências no ecossistema Radix. Com apenas a adição da propriedade "multiple" no componente raiz, o comportamento do select é transformado, simplificando drasticamente o trabalho do desenvolvedor. Além do multi-select, o Base UI traz componentes robustos como Combo Box e Auto Complete, que antes exigiam bibliotecas externas ou implementações manuais complexas. O autor enfatiza que esses novos componentes são fruto de uma escuta ativa da comunidade e das necessidades reais de desenvolvimento moderno. Essa expansão do catálogo de componentes posiciona o Base UI como uma solução headless muito mais completa para aplicações empresariais.

Estratégias de Estilização e Conclusão

A última parte do vídeo foca em como o Base UI revoluciona a estilização, permitindo o uso de funções dentro da propriedade className. Isso elimina a necessidade de lidar com strings gigantescas de Tailwind baseadas em atributos de dados (data-attributes), tornando o código mais legível e fácil de manter. O autor demonstra como essa técnica funciona perfeitamente com a biblioteca Tailwind Variants, permitindo definir estilos de forma declarativa para cada estado do componente. Ele menciona recursos adicionais como suporte para React Hook Form, animações e diálogos aninhados antes de dar seu veredito final. Embora não recomende a migração imediata de projetos estáveis, ele afirma categoricamente que o Base UI é a escolha padrão para qualquer novo projeto React em 2026.

Community Posts

View all posts