Utilitários Personalizados
Crie utilitários personalizados com @utility, variantes personalizadas com @variant e use plugins no Tailwind CSS v4.
Busque em todas as páginas da documentação
Crie utilitários personalizados com @utility, variantes personalizadas com @variant e use plugins no Tailwind CSS v4.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida - pronto para copiar e colar.
/* globals.css */
@import "tailwindcss";
/* Utilitário personalizado - gera uma única classe */
@utility container-prose {
max-width: 65ch;
margin-inline: auto;
padding-inline: 1.5rem;
}
/* Utilitário personalizado com suporte responsivo/hover (automático) */
@utility text-balance {
text-wrap: balance;
}
/* Variante personalizada */
@variant hocus (&:hover, &:focus-visible);
@variant scrolled (&:where([data-scrolled]));
/* Usando um plugin estilo v3 via @config */
@config "./tailwind.config.js";// Uso
<div className="container-prose">
<h1 className="text-balance hocus:text-blue-600">Utilitários Personalizados</h1>
</div>
<header data-scrolled className="scrolled:bg-white scrolled:shadow">Quando usar isso: Quando os utilitários integrados do Tailwind não cobrem um padrão específico que você usa repetidamente - crie um utilitário personalizado uma vez e use-o em todos os lugares.
/* globals.css */
@import "tailwindcss";
/* Utilitários de layout */
@utility stack {
display: flex;
flex-direction: column;
}
@utility center {
display: flex;
align-items: center;
justify-content: center;
}
@utility container-narrow {
max-width: 42rem;
margin-inline: auto;
padding-inline: 1rem;
}
/* Utilitários visuais */
@utility glass {
background: rgb(255 255 255 / 0.8);
backdrop-filter: blur(12px);
border: 1px solid rgb(255 255 255 / 0.2);
}
@utility gradient-text {
background: linear-gradient(to right, var(--color-primary), var(--color-secondary, #8b5cf6));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
@utility scrollbar-hidden {
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}
/* Variantes interativas */
@variant hocus (&:hover, &:focus-visible);
@variant group-hocus (:merge(.group):hover &, :merge(.group):focus-visible &);
@variant aria-current (&[aria-current="page"]);
@variant keyboard-focus (&:focus-visible);
/* Variantes de estado */
@variant loading (&[data-loading]);
@variant empty-state (&:where(:empty, [data-empty]));
@theme {
--color-primary: #2563eb;
}export function CustomUtilitiesDemo() {
return (
<div className="container-narrow stack gap-8 py-12">
<h1 className="gradient-text text-4xl font-bold">
Utilitários Personalizados em Ação
</h1>
<nav className="glass sticky top-0 z-10 rounded-xl p-4">
<ul className="flex gap-4">
<li>
<a href="#" className="rounded px-3 py-1 hocus:bg-gray-100 aria-current:font-bold" aria-current="page">
Home
</a>
</li>
<li>
<a href="#" className="rounded px-3 py-1 hocus:bg-gray-100">Sobre</a>
</li>
<li>
<a href="#" className="rounded px-3 py-1 hocus:bg-gray-100">Contato</a>
</li>
</ul>
</nav>
<div className="scrollbar-hidden flex gap-4 overflow-x-auto pb-2">
{Array.from({ length: 10 }, (_, i) => (
<div key={i} className="shrink-0 center size-24 rounded-lg bg-gray-100 text-sm font-medium">
Card {i + 1}
</div>
))}
</div>
<button
data-loading
className="rounded bg-blue-600 px-4 py-2 text-white loading:opacity-50 loading:cursor-wait"
>
Enviar
</button>
</div>
);
}O que isso demonstra:
@utility para classes utilitárias compostas reutilizáveis@variant para seletores de estado/pseudo personalizadosaria-current, data-loading@utility nome { ... } cria uma classe utilitária .nome na camada de utilitáriosmd:nome), de estado (hover:nome) e outros@variant nome (seletor) cria um modificador que é aplicado quando o seletor corresponde@variant hocus (&:hover, &:focus-visible)& em seletores de variante representa o elemento ao qual a variante é aplicada@layer components em v3Utilitário funcional (com valores) via @theme:
/* Você não pode criar utilitários personalizados de valor arbitrário com @utility.
Em vez disso, defina valores de tema e use utilitários integrados. */
@theme {
--spacing-page: 2rem;
--spacing-section: 4rem;
--width-content: 65ch;
--width-wide: 90rem;
}
/* Agora use: p-page, gap-section, max-w-content, max-w-wide */Usando plugins v3:
// tailwind.config.js (necessário apenas para plugins)
export default {
plugins: [
require("@tailwindcss/typography"),
require("@tailwindcss/forms"),
],
};/* globals.css */
@import "tailwindcss";
@config "./tailwind.config.js";
/* Agora as classes prose e form-* estão disponíveis */Combinando com aninhamento CSS:
@utility card {
border-radius: 0.75rem;
border: 1px solid var(--color-border);
padding: 1.5rem;
background: var(--color-surface);
& > h2 {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
& > p {
color: var(--color-muted-foreground);
}
}Seletores de variante complexos:
/* Estado aberto (para detalhes/diálogo) */
@variant open (&[open], &[data-state="open"]);
/* Variante de estado pai */
@variant sidebar-open (:merge(.sidebar-open) &);
/* Variante de impressão é integrada, mas mídia personalizada: */
@variant portrait (@media (orientation: portrait));
@variant touch (@media (pointer: coarse));// Utilitários personalizados são CSS - sem impacto no TS
// Mas você pode criar um mapa de utilitários para documentação:
const customUtilities = {
"container-prose": "max-width: 65ch centralizado com padding inline",
"glass": "fundo de vidro fosco com blur de fundo",
"gradient-text": "preenchimento gradiente no texto",
"scrollbar-hidden": "oculta a barra de rolagem em todos os navegadores",
} as const;
type CustomUtility = keyof typeof customUtilities;Nomes de @utility devem ser identificadores únicos - Sem pontos, dois pontos ou espaços. @utility my-card funciona; @utility my.card não.
Utilitários personalizados não podem aceitar argumentos - @utility spacing($value) não existe. Solução: Defina valores de tema e use utilitários integrados (p-page, gap-section).
Compatibilidade de plugins - Nem todos os plugins v3 funcionam com v4 ainda. Solução: Verifique a documentação do plugin para suporte v4, ou replique o CSS do plugin com @utility.
@config apenas para plugins - Usar @config com uma configuração v3 completa pode conflitar com @theme. Solução: Coloque apenas o registro do plugin na configuração JS; mova todos os valores de tema para @theme.
Especificidade da variante - @variant usa o seletor que você fornece. Se o seu seletor tiver alta especificidade, ele pode substituir outros estilos inesperadamente. Solução: Use :where() para zerar a especificidade onde necessário.
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
@apply | Você quer compor utilitários Tailwind existentes em uma classe | Você pode usar @utility diretamente (mais limpo) |
| Abstração de componente | O padrão inclui estrutura HTML, não apenas estilos | Você só precisa de uma classe CSS |
| Plugins Tailwind (JS) | Você precisa de geração dinâmica de utilitários com valores | Um @utility estático atende sua necessidade |
| Plugins PostCSS | Você precisa de transformações além do escopo do Tailwind | Os recursos integrados do Tailwind são suficientes |
@utility nome { ... } cria uma nova classe utilitária na camada de utilitários@apply compõe utilitários Tailwind existentes em uma classe@utility é mais limpo e feito sob medida para utilitários personalizados em v4Sim. Um utilitário definido com @utility funciona automaticamente com md:, hover:, dark:, e todos os outros modificadores.
@variant hocus (&:hover, &:focus-visible);Uso: <a className="hocus:text-blue-600">Link</a>
Não. @utility não pode aceitar argumentos. Em vez disso, defina valores de tema e use utilitários integrados:
@theme {
--spacing-page: 2rem;
}
/* Agora use p-page, gap-page, etc. */@import "tailwindcss";
@config "./tailwind.config.js";Coloque apenas o registro do plugin na configuração JS. Mantenha todos os valores de tema em @theme.
@utility card {
border-radius: 0.75rem;
padding: 1.5rem;
& > h2 {
font-size: 1.25rem;
font-weight: 600;
}
}Sim, o aninhamento CSS nativo é suportado dentro de @utility.
Os nomes devem ser identificadores únicos. Hífens são permitidos (my-card), mas pontos, dois pontos e espaços não são (my.card falhará).
@variant loading (&[data-loading]);Uso: <button data-loading className="loading:opacity-50">
O seletor da variante tem alta especificidade. Corrija usando :where() para zerar a especificidade: @variant loading (&:where([data-loading])).
Valores de tema da configuração JS podem conflitar com valores @theme em CSS. Use @config apenas para registro de plugin; mova todos os valores de tema para @theme.
const customUtilities = {
"container-prose": "max-width: 65ch centralizado com padding inline",
"glass": "fundo de vidro fosco com blur de fundo",
} as const;
type CustomUtility = keyof typeof customUtilities;Revisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥