Cambiar tema

Solución de problemas comunes de shadcn/ui: conflictos de estilos, componentes que no renderizan y errores de tipos

Easton editorial illustration: responsive layout folding board

Miras el botón en pantalla: debería ser un botón azul elegante, pero parece un <button> HTML cualquiera, sin ni siquiera bordes redondeados.

En los últimos tres meses he tropezado con más problemas que líneas de código útiles. Conflictos de estilos, componentes que no renderizan, errores de TypeScript: casi forman parte del «paquete» de shadcn/ui, y en cada proyecto nuevo aparecen uno o dos.

Hoy reúno estos problemas frecuentes y sus soluciones para que evites parte del camino.


Diagnóstico de conflictos de estilos

Los conflictos de estilos son lo más habitual: representan unas cuatro de cada diez incidencias. Las causas principales son estas:

Conflictos de variables CSS

shadcn/ui usa variables CSS para los colores del tema, definidas en globals.css:

:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 2%;
}

El problema aparece cuando el proyecto ya tenía su propia configuración de tema, o si modificaste los colores de Tailwind antes de instalar shadcn/ui: las dos configuraciones pueden chocar.

¿Cómo diagnosticarlo?

Abre globals.css y comprueba que todas las variables CSS estén presentes. Luego revisa la sección colors de tailwind.config.js:

module.exports = {
  theme: {
    extend: {
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
      },
    },
  },
}

Ambos lados deben corresponderse. Si falta una variable, el estilo asociado no se aplicará.

Mi experiencia: antes de instalar shadcn/ui, respalda tailwind.config.js y globals.css. Tras la instalación, compara ambos archivos y restaura manualmente la configuración que se haya sobrescrito.

Shadow DOM y conflictos con Tailwind

Este caso es curioso. Shadow DOM sirve para aislar estilos, pero las clases de Tailwind no atraviesan su límite.

El escenario típico es el componente Dialog. DialogContent se renderiza con Portal en document.body, fuera del Shadow DOM, y los estilos desaparecen.

Hay dos soluciones:

La primera: no usar Shadow DOM:

const MyDialogWC = r2wc(MyDialog, {
  shadow: null  // desactivar Shadow DOM
});

Así el Portal funciona, pero pierdes el aislamiento de estilos. Tendrás que gestionar los estilos globales con cuidado y vigilar conflictos de nombres de clase.

La segunda: usar Safelist para forzar la inclusión de clases:

// tailwind.config.js
module.exports = {
  safelist: [
    'bg-primary',
    'text-primary-foreground',
    'hover:bg-primary/90',
    'bg-red-500',
    'h-9',
    'h-10',
    'px-3',
    'px-4',
  ],
}

Garantiza que se generen los estilos, pero Safelist aumenta el tamaño del CSS. Hay que sopesarlo.

Convivencia con otras bibliotecas de UI

Si el proyecto ya usa MUI (Material-UI) y quieres migrar a shadcn/ui, aparecerán conflictos de estilos.

La raíz está en Preflight de Tailwind: restablece los estilos por defecto del navegador. Los de MUI también se resetean y los componentes se ven mal.

Intentos habituales:

Algunos desactivan Preflight:

module.exports = {
  corePlugins: {
    preflight: false,  // desactivar Preflight
  },
}

Pero tiene efectos secundarios: los estilos de Tailwind también se ven afectados y algunos componentes pueden fallar.

Mejor enfoque:

Usa el prefix de Tailwind para prefijar todas las clases:

module.exports = {
  prefix: 'tw-',  // tw-bg-blue-500 en lugar de bg-blue-500
}

Así las clases de Tailwind no chocan con las de MUI. Tendrás que anteponer tw- manualmente a cada clase, lo cual es algo tedioso.

Mi recomendación: si ya hay muchos componentes MUI, no migres todo de golpe. Usa prefix para convivir: shadcn/ui en lo nuevo y MUI en lo existente, migrando poco a poco.

Configuración de Tailwind sobrescrita

Este problema me ha pillado varias veces.

Tras ejecutar npx shadcn-ui@latest init, el archivo de Tailwind se sobrescribe. Sobre todo el array plugins: si tenías @tailwindcss/forms u otros plugins, desaparecen.

Los síntomas son claros: los inputs del formulario se ven raros de repente, o algunos componentes pierden todo el estilo.

Pasos de diagnóstico:

  1. Abre el respaldo de tailwind.config.js de antes de la instalación
  2. Compara con el archivo actual
  3. Restaura los plugins que falten:
module.exports = {
  // ... resto de configuración
  plugins: [
    require("@tailwindcss/forms"),  // restaurar
    require("tailwindcss-animate"),
  ],
}

Prevención: respalda la configuración antes de instalar shadcn/ui, o usa un script que registre todos los plugins.


Diagnóstico cuando los componentes no renderizan

Los estilos están bien, pero el componente no aparece. También es frecuente.

Rutas content mal configuradas

Tailwind necesita saber en qué archivos se usan sus clases para generar el CSS correspondiente. Eso se define en el campo content de tailwind.config.js.

Lo habitual: el directorio de componentes de shadcn/ui no está incluido.

Revisa la configuración:

module.exports = {
  content: [
    './src/app/**/*.{ts,tsx}',
    './src/components/**/*.{ts,tsx}',  // imprescindible
    './app/**/*.{ts,tsx}',
    './pages/**/*.{ts,tsx}',
  ],
}

Si los componentes están en una biblioteca dentro de node_modules, añade también:

content: [
  // ... otras rutas
  './node_modules/@your-ui-lib/**/*.{ts,tsx}',
]

Mi experiencia: cada vez que crees un directorio de componentes nuevo, añade la ruta a content. Si Tailwind no escanea esos archivos, no generará las clases.

Problemas con la ruta de globals.css

shadcn/ui necesita un archivo CSS con las variables del tema. La ruta se configura en components.json.

Lo habitual: ruta incorrecta o varios archivos globals.css.

Cómo diagnosticarlo:

Revisa components.json:

{
  "style": "default",
  "css": "src/app/globals.css",  // esta ruta
}

Luego confirma:

  1. ¿Existe realmente ese archivo?
  2. ¿Solo hay un globals.css en el proyecto?
  3. ¿Se importa correctamente en el archivo principal?

Si hay varios globals.css, elimina los sobrantes y deja uno solo.

Comprobar la importación:

En Next.js, globals.css debe importarse en app/layout.tsx o pages/_app.tsx:

import '@/app/globals.css'  // o './globals.css'

Sin importación, las variables CSS no aplican y los componentes pierden el estilo.

Variables CSS sin definir

A veces globals.css existe, pero faltan variables.

Lo típico es el modo oscuro: activas dark mode y los colores no cuadran, quizá porque no configuraste las variables para oscuro.

Revisa globals.css:

:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
}

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 2%;
}

Las variables bajo .dark deben estar definidas. Si no, los componentes en modo oscuro quedan sin estilo.

Caso especial de Tailwind v4:

Con Tailwind v4 la configuración es distinta:

@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-primary: var(--primary);
}

Ese mapeo @theme inline es obligatorio. Sin él, Tailwind v4 no reconoce esas variables.

Mayúsculas y minúsculas en las rutas de importación

Este fallo me ha costado dos veces.

En Windows los nombres de archivo no distinguen mayúsculas; en Linux/Mac sí. En local todo va bien; en el servidor, error al desplegar.

El síntoma habitual: el componente renderiza en local, pero en producción no encuentra el módulo.

Error típico:

// ❌ incorrecto: B mayúscula en Button
import { Button } from "@/components/ui/Button"

// ✅ correcto: button en minúsculas
import { Button } from "@/components/ui/button"

Los archivos de componentes shadcn/ui están en minúsculas. La ruta de importación también.

Cómo diagnosticarlo:

Revisa todas las importaciones de componentes y comprueba que coincidan con el nombre real del archivo, sobre todo si el error solo aparece en producción.


Diagnóstico de errores de TypeScript

Los errores de TypeScript son menos frecuentes, pero igual de molestos.

Errores de tipo en la prop variant

El Button de shadcn/ui tiene la prop variant para cambiar el estilo (default, destructive, outline, etc.).

El mensaje suele ser:

Type '{ variant: string }' is not assignable to type 'IntrinsicAttributes & ButtonProps'.
Property 'variant' does not exist on type 'IntrinsicAttributes & ButtonProps'.

Causa:

En la definición de tipos del Button, la prop variant no se exporta correctamente.

Cómo diagnosticarlo:

Abre components/ui/button.tsx y revisa la definición de variant:

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
      },
    },
  }
)

interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  // VariantProps debe estar aquí
}

Si falta VariantProps<typeof buttonVariants>, desaparece el tipo de variant.

Mi experiencia: ante este error, revisa primero la definición de tipos del componente y confirma que VariantProps se hereda bien.

Incompatibilidad de versiones de React

Con React 19, si alguna dependencia aún no lo soporta, aparecen errores de tipos.

El mensaje suele ser:

npm error ERESOLVE unable to resolve dependency tree
npm error Found: [email protected]

Dos soluciones:

Forzar la instalación:

npm install --legacy-peer-deps
# o
npm install --force

Ignora los requisitos de peer dependency, pero puede haber problemas de compatibilidad.

O bajar la versión de React:

npm install react@18 react-dom@18

Usa React 18 hasta que las dependencias se actualicen.

Mi recomendación: en proyectos nuevos, React 18 es más estable. Pasa a React 19 cuando shadcn/ui y el resto de dependencias lo soporten de forma clara.

Problemas de tipos con React Hook Form

El Form de shadcn/ui con React Hook Form y Zod puede dar errores de mapeo de tipos.

El mensaje suele ser:

Type 'info.${number}.fileName' is not assignable to type '"info" | "info.0" | "info.0.fileName"'

Es un problema de tipos en campos dinámicos: el tipo del schema Zod no coincide con el de la prop name de FormField.

Solución:

Asegura la inferencia correcta del schema:

const formSchema = z.object({
  email: z.string().email(),
  password: z.string(),
})

type FormValues = z.infer<typeof formSchema>  // imprescindible

const form = useForm<FormValues>({
  resolver: zodResolver(formSchema),
})

La prop name de FormField coincidirá con los campos del schema.

Mi experiencia: los formularios dinámicos (por ejemplo con useFieldArray) son más complejos. Revisa con cuidado el schema Zod y la inferencia de TypeScript.

Dependencias de tipos faltantes

A veces TypeScript falla porque no están instalados @types/react o @types/react-dom.

El mensaje puede ser:

Could not find a declaration file for module 'react'

Solución:

npm install -D @types/react @types/react-dom

Después, reinicia el servidor de TypeScript (en VSCode: Ctrl+Shift+P → «TypeScript: Restart TS Server»).

Prevención: instala las dependencias de tipos desde el inicio del proyecto. No esperes al primer error.


Buenas prácticas y prevención

Tras tantos tropiezos, esto es lo que recomiendo para prevenirlos.

Gestión de la configuración

Respaldar archivos de configuración:

Antes de instalar shadcn/ui o modificar Tailwind:

cp tailwind.config.js tailwind.config.js.backup
cp globals.css globals.css.backup

Tras instalar, compara y fusiona los cambios manualmente.

Un solo archivo de configuración:

Un proyecto, un tailwind.config.js y un globals.css. Varios archivos generan conflictos.

Rutas content completas:

Incluye todos los directorios de componentes:

content: [
  './src/**/*.{ts,tsx}',        // comodín para cubrir todo
  './app/**/*.{ts,tsx}',
  './pages/**/*.{ts,tsx}',
  './components/**/*.{ts,tsx}',
]

Gestión de versiones de dependencias

Revisar peerDependencies:

Antes de instalar un paquete nuevo:

npm info <package> peerDependencies

Si exige React 18 y usas React 19, valora la compatibilidad.

Actualizar dependencias de tipos:

npm update @types/react @types/react-dom

Mantén las declaraciones alineadas con la versión de React.

Estrategia de pruebas

Probar justo después de instalar:

Cuando termines de instalar shadcn/ui, prueba los estilos de inmediato:

  1. Crea una página sencilla con varios componentes shadcn/ui
  2. Comprueba que los estilos se ven bien
  3. Prueba el cambio a modo oscuro
  4. Ejecuta la compilación de TypeScript

Probar en entorno de producción:

Que funcione en local no garantiza producción:

npm run build
npm run preview

Tras el build, previsualiza y verifica estilos y tipos.


Resumen

En la práctica, los problemas habituales de shadcn/ui se concentran en tres áreas:

  1. Conflictos de estilos: configuración sobrescrita, variables CSS en conflicto, convivencia con otras bibliotecas de UI
  2. Componentes que no renderizan: rutas content incorrectas, problemas con globals.css, sensibilidad a mayúsculas en importaciones
  3. Errores de TypeScript: tipos de variant faltantes, incompatibilidad de React, dependencias de tipos ausentes

Ante un problema, sigue este orden:

  1. Revisa la configuración (tailwind.config.js, globals.css)
  2. Revisa las rutas (content, importaciones)
  3. Revisa las definiciones de tipos (componentes, versiones de dependencias)

Si empiezas con shadcn/ui, prueba todo el flujo en un proyecto vacío. Cuando conozcas la configuración y estos fallos típicos, úsalo en un proyecto real.

shadcn/ui es muy útil, pero la configuración tiene su complejidad. Con estos métodos de diagnóstico, los problemas dejan de ser un susto.

FAQ

¿Por qué pierdo todos los estilos después de instalar shadcn/ui?
La causa más habitual es que la configuración de Tailwind se sobrescribe. Comprueba:

• Si el array plugins de tailwind.config.js está completo
• Si la ruta de globals.css es correcta
• Si todas las variables CSS están definidas

Solución: respalda la configuración antes de instalar, compara las diferencias después y restaura manualmente lo que falte.
¿Por qué los estilos de los componentes fallan al cambiar al modo oscuro?
Revisa si las variables CSS bajo la clase .dark en globals.css están completas:

• La clase .dark debe existir
• Todas las variables del tema deben redefinirse
• En Tailwind v4 hace falta mapear las variables con @theme inline
¿Puede shadcn/ui convivir con MUI?
Sí, pero hay que configurar un prefix de Tailwind:

• Establece prefix: 'tw-' para prefijar todas las clases de Tailwind
• Usa shadcn/ui en componentes nuevos y conserva MUI en los antiguos
• Migra de forma gradual, no cambies todo de golpe

No se recomienda desactivar Preflight, porque afecta a los estilos de Tailwind.
¿Qué hago si la prop variant de Button da error de TypeScript?
Revisa la definición de tipos del componente Button:

• VariantProps<typeof buttonVariants> debe heredarse
• Asegúrate de que el archivo del componente exporta los tipos completos
• Instala @types/react y @types/react-dom

Si faltan tipos, vuelve a ejecutar npx shadcn@latest add button para instalar el componente.
¿Se puede usar shadcn/ui con React 19?
Sí, pero hay que gestionar la compatibilidad:

• Al instalar, usa --legacy-peer-deps o --force
• O especifica la versión de react-is en overrides de package.json
• En proyectos nuevos, React 18 es más estable hasta que las dependencias se actualicen
¿Por qué el componente funciona en local pero en producción falla al no encontrar el módulo?
Suele ser un problema de mayúsculas/minúsculas en las rutas de importación:

• Los archivos de componentes shadcn/ui están en minúsculas (button.tsx)
• La ruta de importación debe coincidir (@/components/ui/button)
• Windows no distingue mayúsculas; Linux/Mac sí: en local puede pasar y en producción fallar

Revisa todas las importaciones y asegúrate de que las rutas coincidan exactamente.

10 min de lectura · Publicado el: 2 abr 2026 · Actualizado el: 21 ago 2026

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog