Pular para o conteúdo

Shadcn acaba de resolver o maior problema do Tailwind

Ver no idioma original →

Autoria: Better Stack · Assistir no YouTube

Vídeo de autoria do canal indicado, não da IANIA; todos os direitos pertencem ao criador. Transcrição, resumo e tradução gerados automaticamente; o conteúdo no idioma original é preservado na versão em idioma original.

Idioma original: inglês

Vídeo original: Shadcn Just Fixed Tailwind’s Biggest Problem · Canal: Better Stack · 06:21 · Assistir no YouTube

Tópicos: Agentes de IA, Engenharia de software com IA, Ferramentas de desenvolvimento com IA

O vídeo apresenta um linter do Shadcn para ajudar a aplicar regras de sistemas de design em projetos Tailwind V4, especialmente quando agentes de IA escrevem código. Suas seis regras detectam estilos não permitidos, cores não definidas no tema, valores arbitrários, estilos inline, classes desconhecidas e classes dinâmicas. O linter pode obter informações dos componentes e tokens existentes e fornecer mensagens de erro que orientam o agente sobre como corrigir o código. Há limitações: ele não verifica CSS puro, não decide se novos tokens pertencem ao sistema de design e, por enquanto, está disponível apenas para Oxlint e ESLint.

  • O linter busca impedir que agentes de IA adicionem estilos que violem o sistema de design do projeto.
  • Uma avaliação com oito tarefas mostrou que o uso do linter reduziu a zero as violações observadas nos testes.
  • A regra no restyle permite ajustes de layout, mas impede mudanças não autorizadas em espaçamento, cor, tipografia, formato, efeitos e movimento.
  • As mensagens de erro podem aproveitar as variantes e configurações dos componentes, oferecendo orientações específicas para corrigir o código.
  • As seis regras incluem controles para estilos, cores brutas, valores arbitrários, estilos inline, classes desconhecidas e classes estáticas.
  • Contratos por componente e mensagens personalizadas permitem adaptar as regras ao sistema de design.
  • O linter não analisa CSS puro nem determina se novos tokens adicionados ao tema são apropriados; essa revisão continua sendo necessária.
  • O projeto precisa ter um sistema de design e variantes de componentes para que o linter tenha regras que possa aplicar.
  • No momento, há suporte para Oxlint e ESLint, mas não para Biome.
Início Capítulo Resumo
00:00 O problema de aplicar sistemas de design no Tailwind O vídeo apresenta o linter e explica como estilos adicionados por agentes podem violar as convenções do sistema de design.
01:37 Como funcionam as regras básicas A regra no restyle e as mensagens de erro mostram como o linter limita alterações e orienta a correção do código.
03:12 As seis regras do linter O vídeo percorre regras para valores arbitrários, cores, estilos inline, classes desconhecidas e classes estáticas.
04:16 Personalização com contratos e mensagens Contratos por componente e mensagens personalizadas permitem adaptar as verificações ao sistema de design.
05:19 Limitações e requisitos O linter não verifica CSS puro nem avalia novos tokens, exige componentes com variantes e ainda não oferece suporte a Biome.

É um linter voltado primeiro para agents, criado para sistemas de design no Tailwind. — 00:00

O botão é responsável pelo próprio espaçamento. — 02:09

O erro informa qual é o token do tema mais próximo. — 03:44

O linter só pode verificar as regras. Ele não pode decidir se um novo laranja realmente pertence ao seu sistema de design. — 05:49

  • Tailwind V4 (ferramenta): Versão do Tailwind compatível com o linter apresentado no vídeo.
  • shadcn/ui (pessoa): Criador associado ao linter apresentado para aplicar regras de sistemas de design em projetos Tailwind.
  • shadcn/ui (ferramenta): Biblioteca de componentes mencionada como exemplo de projeto que já usa variantes.
  • Oxlint (ferramenta): Linter no qual o plugin apresentado pode ser usado.
  • ESLint (ferramenta): Linter compatível com o plugin apresentado.
  • StyleX (ferramenta): Alternativa ao Tailwind citada no contexto de controle dos estilos.
  • CVA (ferramenta): Configuração usada no componente de botão, cujas opções o linter pode consultar.
  • Biome (ferramenta): Linter para o qual ainda não há um plugin equivalente disponível, segundo o vídeo.
  • sistema de design (conceito): Conjunto de regras, tokens e variantes que define os estilos permitidos para os componentes.
  • contratos (conceito): Regras configuráveis por componente, associadas ao nome do componente por uma expressão regular.

00:00 A Shadcn acabou de lançar um linter para tentar resolver o maior problema do Tailwind hoje: sistemas de design. Com a ascensão dos agentes de IA, o Tailwind nunca teve uma ótima maneira de impor um sistema de design. Então, talvez você tenha notado que, às vezes, a IA adiciona estilos próprios que não queríamos de verdade. Esse é um dos principais motivos pelos quais as pessoas têm recorrido a alternativas como StyleX, mas agora a Shadcn tem uma solução para isso. É um linter pensado primeiro para agents e feito para sistemas de design com Tailwind. Então, vamos direto ao ponto e ver o que ele faz. Vamos começar entendendo o que esse linter realmente faz. No Tailwind, um nome de classe

00:33 pode ser uma string. O TypeScript não impõe nada além disso, o que significa que você pode colocar um padding para sobrescrever o padding de um botão que controla o próprio espaçamento interno. Você também pode adicionar uma cor aleatória, como background pink 500, a um componente que já usa uma cor do tema, ou simplesmente usar uma quantidade arbitrária de padding, como 13 pixels, quando seu sistema de design já tem uma escala de espaçamento que vai de 12 a 16. Atualmente, nada disso gera erros no seu código, e esses problemas só são identificados quando você revisa o código ou adiciona um monte de regras a um arquivo Markdown para outro agent revisar por você. Mas o Markdown não é ótimo para impor regras. Ele

01:06 não é tão rigoroso quanto um linter. A Shadcn chegou a analisar os números. Ela configurou oito tarefas que tentam fazer o agent se desviar do sistema, com prompts como: “adicione um botão de exclusão; o design pede que ele seja rosa, com cantos em formato de pílula”; “crie um cartão de estatísticas que corresponda exatamente a este mock, com 13 pixels de padding e raio de borda de 10 pixels”; ou “faça o cartão de preços se destacar bastante”. Dá para ver aqui que todos os modelos produziram muitas violações do sistema de design ao executar essas tarefas, mas, quando usaram o linter, o número caiu para zero. Agora que sabemos que o linter funciona, como usamos ele? Bem, é um plugin

01:37 para Oxlint ou ESLint, e funciona em qualquer projeto com Tailwind V4. Você não precisa estar usando Shadcn UI. Podemos começar com uma regra chamada no restyle, permitindo layout. Isso significa, basicamente, que as páginas podem posicionar um componente usando coisas como margem, largura, flex e hidden, mas não podem mudar o estilo dele. Então, não podem adicionar padding, cor, tipografia, forma, efeitos ou movimento. Se fizerem isso, o linter vai gerar um erro como este: “P4 não é permitido em button. O button controla o próprio espaçamento. Use um tamanho padrão ou margem aqui, ou um gap no elemento pai para criar espaço ao redor. Adicione um tamanho ao componente

02:09 somente se o sistema de design pedir isso explicitamente.” O legal dessas mensagens de erro é que algo como a lista de tamanhos não é definido pelo linter. Na verdade, ele lê a configuração do CVA no próprio componente button. Então, se eu adicionar um tamanho extra, o erro vai incluí-lo como uma opção. O mesmo vale, basicamente, para qualquer recurso do Tailwind que possa mudar o estilo. Então, se tentarmos adicionar uma cor aqui, ele vai nos dizer que só podemos usar as cores definidas no componente. E, obviamente, a vantagem disso é receber mensagens de erro muito boas que um agent pode ler e entender como corrigir. Isso também pode economizar tokens, porque ele

02:39 não precisa carregar todos os seus arquivos Markdown de design para entender o que está correto. O linter pode simplesmente dar uma indicação bem específica. Essa é a utilização básica da nossa primeira regra, no restyle, mas há muitas opções de personalização para adaptá-la ao seu sistema de design. Voltaremos a isso daqui a pouco. Primeiro, vamos conferir as outras cinco regras, porque são seis no total. No raw colors é uma regra para impedir que você digite coisas como background pink 500, use uma cor que não existe ou escreva uma cor incorretamente. A cor precisa ser definida no tema. E, mais uma vez, isso ajuda o agent, informando diretamente o que é permitido. Funciona até com SVGs. Então, se

03:12 você tentar usar um fill fixo em um path, vai receber um erro dizendo para usar current color com uma classe de cor de texto. Em seguida, temos no arbitrary values. Ela faz exatamente o que diz. Algo como usar padding com 13 pixels entre colchetes cria um valor fixo que não pertence à escala de tokens. Use P3.25 em vez disso. É o mesmo valor na escala. Ou algo como rounded 10 pixels entre colchetes gera a sugestão de usar rounded large, porque o linter consegue ler meu token de raio e saber que esse é o valor equivalente a 10 pixels. Um dos exemplos mais legais de como essa regra realmente entende seu sistema de design aparece quando

03:44 você tenta definir uma cor de fundo aleatória. O erro informa qual token do tema é o mais próximo, o que dá um contexto muito útil para o agent. As demais regras são bem autoexplicativas. Há uma regra para impedir estilos inline, outra para impedir o uso de classes desconhecidas e uma para impor classes estáticas. Essa última é interessante porque o linter não consegue ver qual será essa classe, já que ela é dinâmica dentro desse template literal. Então, essa regra incentiva você a mudar a forma como lida com esses casos, para que o linter ainda consiga fazer seu trabalho com eficiência. Essas são as seis regras do linter, mas, como mencionei antes, há muitas opções de personalização para realmente

04:16 adaptá-lo ao seu sistema de design. É aí que entram os contratos. São regras por componente, associadas por uma expressão regular ao nome do componente. Neste exemplo, defini que podemos mudar a tipografia do título de um cartão, mas não a família nem o peso da fonte, e que o conteúdo do cartão pode mudar o espaçamento, mas não a tipografia. Assim, text large nesse título passa sem erros, e padding six no conteúdo também passa, mas tentar mudar o peso da fonte do título ainda gera um erro, como esperado. Outra ótima opção nessas configurações são as mensagens personalizadas. Cada regra e tipo de regra aceita uma mensagem com espaços reservados, preenchidos com informações do seu

04:47 código. Então, no contrato do meu button, configurei a mensagem para dizer: “defina a largura no contêiner pai, não em button”, para layout, e também: “button controla o próprio padding; use um tamanho de button, com um modelo para os tamanhos”. Essas informações serão preenchidas com base no meu próprio sistema de design. Você também pode definir uma nota global, para que cada ocorrência venha acompanhada dessa mensagem no final. Isso é útil para dar dicas ou contexto extra ao agent, talvez indicando onde estão sua documentação ou suas diretrizes. Se você já tem um sistema de design, pode dar um pouco mais de trabalho começar a usar esse linter, já que é preciso configurá-lo para o seu sistema de design, mas

05:19 ele parece flexível o bastante para lidar com a maioria dos sistemas, e tenho certeza de que um agent de IA pode ajudar você a começar. A última coisa que quero comentar é o que esse linter não consegue fazer. Ele não consegue ver CSS puro. Então, se houver uma cor fixa no seu arquivo CSS global ou em um @apply, ele não consegue impor regras nesse caso. Também não consegue rastrear seletores pais até os elementos filhos. Ele só acompanha os valores das classes por um nível de profundidade dentro de um arquivo, e um token de tema totalmente novo é, por definição, permitido pelo sistema. Portanto, um agent que adiciona uma cor ou um tom ao seu sistema de design para contornar a regra ainda vai passar. Isso significa que você ainda precisa revisar

05:49 os tokens e as variantes que o agent está adicionando. O linter só consegue verificar as regras. Ele não consegue decidir se um novo tom de laranja realmente pertence ao seu sistema de design. Essa decisão ainda cabe a você, mas, com sorte, esse linter deve reduzir um pouco desse trabalho extra. Outra coisa a considerar se você está pensando em usar isso: a API dos seus componentes é rigorosa o bastante para impor essas regras? Se o seu button simplesmente aceita qualquer nome de classe e não tem variantes, não há nada que o linter possa sugerir. Então, o pré-requisito é que você já tenha um sistema de design e use variantes de verdade. Para ser justo, se você usa shadcn/ui, já tem isso. Então, a maioria

06:21 As pessoas provavelmente vão ficar bem. A desvantagem final é que, por enquanto, isso só está disponível no oxlint e no eslint. Ainda não há um plugin do biome para isso, mas existe uma issue aberta sobre o assunto no GitHub deles. Então, esperamos ver isso em breve. Bom, esse é o novo linter do shadcn. São seis regras que ajudam você a aplicar seu sistema de design, o que é muito útil numa era em que a IA escreve a maior parte do código. Estou curioso para saber se isso resolve algum dos problemas que você encontrou ou se ainda está pensando em mudar para algo como StyleX. Me conte nos comentários abaixo. Ah, sim, curta e inscreva-se. E, como sempre, até a próxima. >> [fungada]

Transcrição original

[00:00] Shadcn just released a linter to try and solve the biggest problem with Tailwind today, design systems. With the rise of AI agents, Tailwind has never had a great way to enforce one. So, you may have noticed AI sometimes adds in its own styles we didn’t really want it to. It’s a large reason why people have turned to alternatives like StyleX, but now Shadcn has a solution for that. It’s an agent-first linter built for Tailwind design systems. So, let’s just jump in and see what this does. Let’s start out with what this linter actually does. In Tailwind, a class name

[00:33] can be a string. TypeScript doesn’t enforce anything beyond that, and that means that you can put a padding for override on a button that controls its own padding. You could also add a random color like background pink 500 to a component that already uses a themed color, or just use some arbitrary padding amount like 13 pixels when your design system already has a spacing scale that goes from 12 to 16. Currently, none of these will cause any errors in your code base, and they’ll only be picked up by you actually reviewing the code or just adding a load of rules to a markdown file that another agent can review for you. But, markdown is not great at enforcing things. It is

[01:06] not as strict as a linter can be. Shadcn actually ran the numbers on this. He set up eight tasks that attempt the agent to go off the system with prompts like add a delete button, the design calls for it to be pink with pill corners, build a stats card matching this mock exactly, 13 pixels padding, 10 pixel border radius, or make the pricing card really pop so it stands out. You can see here that every single model produced a lot of design system violations when running these tasks, but when they used the linter, it dropped down to zero. So, now that we know the linter actually works, how do we use it? Well, it’s a plugin

[01:37] for Oxlint or ESLint, and it will work on any Tailwind V4 project. You don’t have to be using Shadcn UI. We can start out with one rule called no restyle, but allowing layout. And this essentially means that pages are allowed to place a component with things like margin, width, flex, and hidden, but they’re not allowed to restyle them. So, they can’t add padding, color, typography, shape, effects, or motion. If they do, it’ll throw an error like this. P4 is not allowed on button. Button owns its spacing. Use a size default or margin here or a gap on the parent for space around it. Add a size in the component

[02:09] only if the design system explicitly calls for one. The cool thing about these error messages here is something like the size list isn’t actually defined by the linter. It’s actually reading my CVA setup in the button component itself. So, if I added an extra size, the error would pick that up as an option. The same goes for basically any tailwind feature that can restyle. So, if we try to add a color here, it would tell us we can only use the ones defined in the component. And obviously, the benefit of this is that you get really nice error messages and an agent can read them and understand how to fix them. This can actually save you on token usage as well because it

[02:39] doesn’t have to load in your full design markdown files to understand what’s correct. The linter can just give it a very specific clue. Now, that’s the basic usage of our very first rule, no restyle, but there is loads of customization options to make it suit your design system, but we’ll come back to that in a minute. First, let’s take a look at the other five rules as there’s actually six in total. No raw colors is a rule to stop you typing in things like background pink 500 or using a color that doesn’t exist or is misspelled. It has to be one that was designed in the theme. And again, it will help the agent out by telling them directly what is allowed. This even works on SVGs. So, if

[03:12] you try to use a hard-coded fill on a path, you get an error saying use current color with a text color class. Next up, we have no arbitrary values. This does what it says on the tin. Something like padding with 13 pixels in the square brackets here gets hard codes an off-token value. Use P3.25 instead. It’s the same value on the scale. Or something like rounded 10 pixels in those square brackets gets use rounded large instead because it can actually read my radius token and know that’s the value that equals 10 pixels. One of the coolest examples of this rule actually understanding your design system is if

[03:44] you try and set a random background color, the error actually tells you what the nearest theme token is, which is super nice context for your agent to have. The rest of the rules are pretty self-explanatory. There’s a rule to stop inline styles, another to stop unknown classes being used, and one to enforce static classes. This one’s interesting because the linter can’t actually see what this class is going to be since it’s a dynamic in that template literal. So, this rule encourages you to change the way that you handle these so the linter can still do its job effectively. Those are our six linter rules though, but as mentioned earlier, there’s lots of customizability to make this actually

[04:16] suit your design system. This is where you would use contracts. These are per component rules matched by a regex on the component name. So, in this example, I said we can change a card title’s typography, but not its font family or weight, and card content can change the spacing, but not the typography. So, now text large on this title passes with no errors, and padding six on the content passes, but trying to change the title’s weight still gives us an error as expected. Another great option in these settings is custom messages. Every rule and type of rule takes a message with placeholders that are filled from your

[04:47] actual code. So, on my button contract here, I’ve set the message to be set to be set width on the parent container, not on button, for layout, and also button owns its padding, use a button size with a template for the sizes. Those will be filled in for me from my own design system. You can also set a global note, so every finding will have this message attached at the end. This is useful to give some extra hints or context to the agent, maybe telling it where your documentation or guidelines are. If you already have a design system in place, this might be a little bit of extra work to actually get started with using this linter as you have to configure it for your design system, but

[05:19] it seems flexible enough that it can handle most systems, and I’m sure an AI agent can help you get started. The final thing I want to talk about is what this linter can’t do. It can’t see plain CSS, so if you have a raw color in your global CSS file or an apply, it can’t enforce rules around that. It also can’t trace parent selectors down to the child. It only follows class values for one hop within a file, and a brand new theme token is on system by definition, so an agent that actually adds color or paint to your design system to get around the rule will still pass. This does mean that you still need to review

[05:49] the tokens and the variants that the agent is adding. The linter can only check the rules. It can’t decide whether a new orange actually belongs in your design system. It’s still on you to check, but hopefully this linter should take out some of that extra work. Something else to think about if you’re considering using this is is your component API actually strict enough to enforce against? If your button simply takes any class name and has no variants, there’s nothing for this linter to suggest. So, the prerequisite is that you actually have a design system in place and use actual variants, which to be fair, if you’re using shadcn/ui, you already have. So, most

[06:21] people will probably be fine. The final downside is that for now this is only available in oxlint and eslint. There is no biome plugin for this yet, but this is an open issue on their GitHub. So, hopefully we see this soon. So, that’s the new shadcn linter. It’s six rules that help you enforce your design system, which is really helpful in an era where AI is writing most of the code. I’m curious if this fixes any of the problems that you’ve run into or if you’re still considering switching to something like StyleX. Let me know in the comments down below. Oh yeah, like subscribe. And as always, see you in the next one. >> [snorts]