Español
no-borrowed-component-styles
Regla de oxlint que reporta un elemento que rearma uno de tus componentes con clases de Tailwind CSS: un Button, Card o Input hecho a mano.
Experimental
Sus heurísticas aún pueden cambiar en una versión minor, agregando o quitando reportes. Viene apagada en la config recomendada.
De un vistazo
| Autofix | Sugerencias en el editor | Design system | Opciones |
|---|---|---|---|
| No | No | Obligatorio (entryPoint) | components, entryPoint |
Qué hace esta regla
Tus componentes guardan las decisiones del design system: <Button> es el color primario, el radio, la altura y el anillo de foco, en un solo lugar. Un <button> que copia las clases de Button — o las reescribe de memoria — se ve igual hoy y se desvía mañana: cuando Button cambia, él no, y nunca tuvo el anillo de foco, el estado deshabilitado ni las variantes. Esta regla lee los componentes que le indicas, y reporta un elemento simple cuyas clases rearman uno de ellos:
text
<button> rebuilds Button: 9 of its 9 style declarations match. Use Button from
components/ui/button.tsx instead, so it follows your design system.Compara lo que hacen las clases, no cómo están escritas:
- cada clase se convierte en sus declaraciones CSS, así que
px-4ypl-4 pr-4, orounded-mdyrounded-t-md rounded-b-md, son el mismo estilo; - el layout queda fuera —
flex,w-full,mt-4,gap-2: dónde se ubica un elemento lo decides tú; - y también las clases detrás de una variant (
hover:,md:,data-[state=open]:), en ambos lados.
Un elemento se reporta cuando comparte al menos 4 declaraciones con un componente, esas son al menos el 60% de todas las declaraciones que pone cualquiera de los dos (las que el elemento agrega cuentan en contra), una de ellas estila la caja — fondo, borde, esquinas o sombra — y ninguno de sus colores difiere de los del componente. La forma de un Button en otro color es otro estilo, y text-sm font-medium por sí solo es cualquier texto.
Solo se comparan elementos nativos (<button>, <div>, <span>), a partir de su string en className o de la llamada a cn() que tenga: el className de un componente se mezcla con sus propios estilos, no es una copia de ellos. Los archivos de los componentes nunca se reportan.
DS-dependiente — necesita settings.tailwindcss.entryPoint para convertir clases en declaraciones. Sin autofix: cambiar un elemento por un componente cambia sus props y su comportamiento.
Cómo lee tus componentes
La regla lee cada archivo de components sin ejecutarlo, y toma:
- una definición con
cva()otv(): sus clases base más el default de cada grupo de variantes, como el componente (Button), y un estilo por cada valor de su primer grupo de variantes (Button variant="outline"); - el primer
classNamede un componente función con nombre en mayúscula — su elemento raíz — cuando es un string o una llamada acn()/clsx():Card,CardHeader.
Un estilo se compara solo si tiene al menos 4 declaraciones, un color y una caja. Se omiten los componentes que pasan className tal cual, o que arman sus clases en runtime.
Opciones
components
string[], default [].
Los archivos y directorios con los componentes de tu design system. Un directorio se lee de forma recursiva, sin los archivos *.test.*, *.spec.*, *.stories.* ni *.d.ts. Las rutas relativas se resuelven como entryPoint: contra el directorio del .oxlintrc.json más cercano, y después contra el directorio de trabajo de oxlint. Sin componentes, la regla no reporta nada.
jsonc
{
"tailwindcss/no-borrowed-component-styles": ["warn", { "components": ["src/components/ui"] }]
}entryPoint
string, opcional. Override por regla de settings.tailwindcss.entryPoint.
Ejemplos
Con el Button y el Card de shadcn/ui en components/ui:
✗ Incorrecto
tsx
// options: { "components": ["components/ui"] }
// Copiado de Button
<button className="inline-flex items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground h-9 hover:bg-primary/90">
Pagar
</button>
// reports: rebuilds Button
// Reescrito de memoria: otro orden, pl-4 pr-4 en vez de px-4, en un link
<a className="bg-primary text-primary-foreground pl-4 pr-4 py-2 h-9 rounded-md text-sm font-medium">
Pagar
</a>
// Un Card, con sus clases mezcladas por cn()
<div className={cn("rounded-xl border bg-card py-6", "text-card-foreground shadow-sm")}>Plan</div>
// reports: rebuilds Card✓ Correcto
tsx
// options: { "components": ["components/ui"] }
// Los componentes mismos
<Button className="mt-4 w-full">Pagar</Button>
// Solo layout
<div className="flex items-center gap-2 p-4" />
// La forma de un Button en un color que ninguna de sus variantes usa es otro estilo
<div className="rounded-md bg-muted px-4 py-2 text-sm font-medium h-9" />
// Sin caja en común: los estilos de texto por sí solos son cualquier texto
<span className="h-9 px-4 py-2 text-sm font-medium text-primary-foreground" />Interacciones con otras reglas
no-default-paletteyno-hardcoded-colorsmantienen los colores de un elemento en tu theme; esta regla mantiene en los componentes los estilos que ellos ya definen.max-class-count: un string de clases largo en un elemento simple suele ser un componente que espera ser extraído — o uno que ya existe, y esta regla lo nombra.no-restylede @shadcn/lint reporta la dirección contraria: clases que reestilan un componente (<Button className="bg-blue-600">). Esta regla reporta un elemento simple reestilado para parecerse a uno. Mira shadcn/ui y @shadcn/lint.
Cuándo desactivarla
- Un elemento que no puede ser el componente. shadcn/ui dibuja un checkbox dentro de un ítem de menú de comandos con las clases de Checkbox, porque un Checkbox real — un botón — no puede ir dentro de una opción. Desactiva esa línea.
- Código que muestra el markup de los componentes, como stories o páginas de docs fuera de
components. - Durante una migración a los componentes: los reportes son la lista de pendientes; deja la regla en
warn.