- Publicado el
¿Qué es shadcn/ui? Su propósito, ventajas y uso en aplicaciones React modernas
- Autores
¿Qué es shadcn/ui? Su propósito, ventajas y uso en aplicaciones React modernas
Los proyectos React modernos suelen afrontar una decisión difícil: ¿utilizar una biblioteca de interfaz ya construida (rápida, pero inflexible) o diseñar tu propio sistema (flexible, pero lento de construir)?
Ahí es donde entra shadcn/ui, un nuevo enfoque del desarrollo de interfaces que te da control total sobre tu código y ofrece a la vez el acabado de una biblioteca de componentes madura.
En esta guía, exploraremos qué es shadcn/ui, por qué se ha vuelto tan popular entre los desarrolladores React y Next.js y cómo puedes utilizarlo para acelerar tu trabajo de interfaz sin perder flexibilidad.
¿Qué es shadcn/ui?
shadcn/ui (a menudo escrito simplemente como shadcn) no es un paquete npm tradicional ni una biblioteca de componentes con temas personalizables como Material UI o Chakra UI.
Es una colección de componentes React de alta calidad y código abierto construidos con:
- Tailwind CSS (para los estilos)
- Radix UI (para primitivas accesibles y sin estilos)
- Lucide Icons (para iconos SVG claros y coherentes)
Pero esta es la diferencia:
En lugar de instalarlo como dependencia, copias el código fuente real de cada componente en tu propio proyecto.
Esto significa que cada botón, diálogo o menú desplegable vive en tu propia base de código, donde tú puedes editarlo, personalizar su tema y controlar sus versiones.
Puedes considerarlo un generador de componentes o un kit inicial de interfaz, no una dependencia.
Cómo funciona
El proyecto shadcn/ui proporciona una herramienta de línea de comandos que genera componentes directamente en tu proyecto:
npx shadcn-ui@latest add button
Este comando descarga un componente Button accesible y ya construido, y lo añade a tu carpeta local components/ui/. Desde ahí puedes personalizarlo, cambiar las clases de Tailwind, ajustar variantes o adaptarlo a tu sistema de diseño.
Cada componente es simplemente React + Tailwind + Radix, sin lógica oculta ni dependencia en tiempo de ejecución.
Por qué los desarrolladores utilizan shadcn/ui
1. Propiedad total del código
A diferencia de las bibliotecas de interfaz en las que dependes de dependencias opacas, shadcn te da el código fuente completo del componente. Puedes:
- Editar directamente los estilos
- Añadir propiedades o variantes
- Integrar lógica personalizada (como análisis de uso o permisos)
Es tu interfaz y tus reglas, sin esperar a que los responsables del mantenimiento fusionen una solicitud de incorporación.
2. Construido sobre bases probadas
Cada componente se construye utilizando:
- Tailwind CSS → estilos basados en utilidades
- Radix UI → primitivas básicas accesibles y sin estilos
- Lucide Icons → iconos SVG modernos
- clsx / tailwind-variants → gestión clara de clases condicionales
Esto garantiza que tus componentes sean accesibles y estén preparados para producción, siguiendo las buenas prácticas de los sistemas de diseño de forma predeterminada.
3. Coherencia y velocidad
Obtienes un punto de partida cohesionado y atractivo para tu interfaz:
- Sistema coherente de espaciado, tipografía y color
- Modo oscuro y temas mediante variables CSS
- Patrones de disposición e interacción listos para usar (menús desplegables, ventanas modales, información emergente)
Puedes empezar a entregar interfaces que parecen diseñadas, sin reinventar cada componente.
4. Sin dependencia del proveedor
Como los componentes son simplemente código, puedes:
- Crear versiones derivadas
- Sustituirlos
- Combinarlos con otras bibliotecas
Si shadcn/ui cambia o deja de cubrir tus necesidades, tus componentes siguen perteneciéndote por completo.
Componentes habituales y ejemplos
Estos son algunos de los componentes más populares de shadcn/ui y su aspecto en funcionamiento.
Ejemplo 1: Botón
import { Button } from '@/components/ui/button'
export default function Example() {
return (
<div className="space-x-2">
<Button>Default</Button>
<Button variant="outline">Outline</Button>
<Button variant="destructive">Delete</Button>
</div>
)
}
Por qué es excelente:
- Variantes integradas como
outline,destructiveyghost. - Temas completamente personalizables con los tokens de diseño de Tailwind.
- Suficientemente sencillo para personalizarlo sin perder coherencia.
Comprender las variantes del botón
Cuando ejecutas:
npx shadcn-ui@latest add button
La herramienta de línea de comandos crea un archivo button.tsx dentro de components/ui/, normalmente así:
// components/ui/button.tsx
import * as React from 'react'
import { cva } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
function Button({ className, variant, size, ...props }: ButtonProps) {
return <button className={cn(buttonVariants({ variant, size, className }))} {...props} />
}
export { Button, buttonVariants }
Entonces, ¿qué son outline, destructive y ghost?
Son variantes de estilo predefinidas en esa configuración buttonVariants. No necesitas definirlas manualmente, vienen con el componente generado de forma predeterminada.
Cada variante corresponde a un patrón diferente de clases de Tailwind:
| Variante | Estilo visual | Uso habitual |
|---|---|---|
default | Botón principal sólido (bg-primary, texto blanco) | Llamada principal a la acción (por ejemplo, “Guardar”, “Enviar”). |
outline | Fondo transparente, borde visible | Acción secundaria o con menor énfasis (“Cancelar”). |
destructive | Color rojo/de peligro (bg-destructive) | Acciones con consecuencias destructivas (“Eliminar”, “Quitar”). |
ghost | Estilo mínimo, efecto sutil al pasar el cursor | Botones de bajo énfasis (por ejemplo, iconos, enlaces secundarios). |
link | Estilo de enlace de texto | Para navegación integrada en el texto. |
Así, cuando escribes:
<Button variant="destructive">Delete</Button>
le indicas al componente Button que utilice el estilo rojo de peligro, porque la variante corresponde a bg-destructive y text-destructive-foreground.
¿Qué son los “tokens de diseño de Tailwind”?
Los “tokens de diseño” son variables con nombre para colores y espaciado utilizadas en todo tu tema. En shadcn/ui, se definen en tu archivo globals.css (o tailwind.config.js) así:
:root {
--background: 0 0% 100%;
--foreground: 222.2 47.4% 11.2%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
/* etc. */
}
Después, Tailwind hace referencia a ellos como “tokens” mediante su sintaxis theme() o clases abreviadas:
className = 'bg-primary text-primary-foreground hover:bg-primary/90'
Estos tokens:
- Mantienen los colores coherentes entre componentes.
- Admiten automáticamente el modo oscuro mediante variables CSS.
- Permiten a diseñadores y desarrolladores compartir un lenguaje visual (por ejemplo, “primary”, “accent”, “destructive”) en lugar de códigos hexadecimales sin procesar.
Por qué esto es útil
- Puedes añadir o modificar variantes (por ejemplo,
success,warning) fácilmente en el mismobutton.tsx. - Tu interfaz mantiene la coherencia visual porque todas las variantes utilizan tokens de diseño compartidos.
- Actualizar tu tema (colores, espaciado, etc.) actualiza al instante todos los componentes.
- Es flexible, utiliza las variantes integradas o amplíalas para adaptarlas a tu marca.
En resumen: Esas variantes (outline, destructive, ghost, etc.) son estilos ya construidos e impulsados por tokens de diseño que puedes ampliar o sobrescribir. Son parte de lo que hace que los componentes de shadcn/ui estén preparados para producción de forma predeterminada, sean coherentes, se adapten al tema y se personalicen fácilmente.
Ejemplo 2: Diálogo (ventana modal)
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
export default function Example() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Confirm Action</DialogTitle>
</DialogHeader>
<p>This action cannot be undone.</p>
</DialogContent>
</Dialog>
)
}
Por qué es excelente: El diálogo utiliza primitivas de Radix internamente, lo que significa que es accesible mediante teclado, compatible con lectores de pantalla y adaptable de forma predeterminada.
Ejemplo 3: Campos de entrada y componentes de formulario
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
export default function LoginForm() {
return (
<form className="space-y-4">
<div>
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="you@example.com" />
</div>
<Button type="submit">Login</Button>
</form>
)
}
Claro, mínimo y fácil de ampliar para cualquier página de autenticación o configuración.
Cuándo utilizar shadcn/ui y cuándo no
✅ Utilízalo cuando
- Creas un producto personalizado (SaaS, panel, aplicación) y quieres una interfaz coherente rápidamente.
- Necesitas control total sobre el diseño y la accesibilidad.
- Ya utilizas Tailwind CSS y Next.js.
❌ Evítalo cuando
- Prefieres un sistema de diseño listo para incorporar (como MUI, Chakra UI).
- No utilizas Tailwind (está estrechamente vinculado a él).
- Quieres avanzar extremadamente rápido sin tocar el código de los componentes.
Primeros pasos (configuración rápida)
Instala Tailwind CSS (si aún no lo has hecho):
npx create-next-app my-app cd my-app npx tailwindcss init -pInicializa shadcn/ui
npx shadcn-ui@latest initAñade componentes
npx shadcn-ui@latest add button card dialog inputImporta y personaliza Tus nuevos componentes aparecerán en
components/ui/.
🧩 shadcn frente a otras bibliotecas de interfaz
| Característica | shadcn/ui | Chakra UI | Material UI | Headless UI |
|---|---|---|---|---|
| Propiedad del código | ✅ Te pertenece | ❌ Controlado por la biblioteca | ❌ Controlado por la biblioteca | ✅ Te pertenece |
| Estilos | Tailwind | Styled System | Emotion / CSS | Tailwind |
| Accesibilidad | ✅ Radix UI | ✅ | ✅ | ✅ |
| Temas | ✅ (variables CSS + Tailwind) | ✅ | ✅ | ⚙️ Personalizados |
| Curva de aprendizaje | 🟢 Baja | 🟢 Media | 🔴 Alta | 🟡 Media |
| Libertad de personalización | 🟢 Total | 🟡 Parcial | 🔴 Limitada | 🟢 Total |
Ideas principales
- shadcn/ui no es un paquete, es un modelo de componentes de copiar y poseer.
- Obtienes control real, sin dependencia del proveedor y una gran experiencia de desarrollo.
- Construido con Tailwind, Radix y patrones modernos de React, es ideal para equipos que quieren una base de diseño clara, accesible y ampliable.
Es el punto intermedio perfecto entre “construirlo todo tú mismo” y “depender de una biblioteca de interfaz pesada”.