Modo Oscuro
El paquete Tailwind v4 soporta el modo oscuro a través de su sistema de tokens semánticos. Dado que todos los colores hacen referencia a variables CSS, cambiar al modo oscuro es simplemente una cuestión de redefinir esas variables.
Cómo Funciona
Los componentes usan clases de utilidad semánticas como bg-primary, text-foreground y border-border. Estas se resuelven en variables CSS (--color-primary, --color-foreground, etc.) que defines en el CSS de tu proyecto. El modo oscuro funciona proporcionando valores alternativos para estas variables bajo un selector oscuro.
Configuración
Usando el Atributo data-theme
Define los valores de los tokens para el modo claro y oscuro usando selectores data-theme:
@theme { --color-background: oklch(1 0 0); --color-foreground: oklch(0.145 0.004 285.823); --color-popover: oklch(1 0 0); --color-popover-foreground: oklch(0.145 0.004 285.823); --color-primary: oklch(0.205 0.006 285.885); --color-primary-foreground: oklch(0.985 0.001 285.823); --color-muted-foreground: oklch(0.556 0.01 285.823); --color-accent: oklch(0.96 0.003 285.823); --color-accent-foreground: oklch(0.205 0.006 285.885); --color-destructive: oklch(0.577 0.245 27.325); --color-border: oklch(0.922 0.004 285.823); --color-input: oklch(0.922 0.004 285.823); --color-ring: oklch(0.87 0.006 285.823);}
[data-theme="dark"] { --color-background: oklch(0.145 0.004 285.823); --color-foreground: oklch(0.985 0.001 285.823); --color-popover: oklch(0.145 0.004 285.823); --color-popover-foreground: oklch(0.985 0.001 285.823); --color-primary: oklch(0.985 0.001 285.823); --color-primary-foreground: oklch(0.205 0.006 285.885); --color-muted-foreground: oklch(0.556 0.01 285.823); --color-accent: oklch(0.269 0.006 285.885); --color-accent-foreground: oklch(0.985 0.001 285.823); --color-destructive: oklch(0.577 0.245 27.325); --color-border: oklch(0.269 0.006 285.885); --color-input: oklch(0.269 0.006 285.885); --color-ring: oklch(0.369 0.006 285.885);}Activa el modo oscuro estableciendo el atributo:
function App() { const [dark, setDark] = useState(false);
return ( <div data-theme={dark ? "dark" : "light"}> <button onClick={() => setDark(!dark)}>Toggle Theme</button> <DatePicker value={value} onChange={setValue} /> </div> );}Usando la Clase .dark
Si tu framework usa una clase .dark (p. ej., Next.js con next-themes), define los tokens bajo esa clase:
@theme { /* Light tokens */ --color-background: oklch(1 0 0); --color-foreground: oklch(0.145 0.004 285.823); /* ... */}
.dark { --color-background: oklch(0.145 0.004 285.823); --color-foreground: oklch(0.985 0.001 285.823); /* ... */}Usando la Preferencia del Sistema
Usa @media (prefers-color-scheme: dark) para seguir la configuración del sistema operativo:
@theme { /* Light tokens */ --color-background: oklch(1 0 0); --color-foreground: oklch(0.145 0.004 285.823); /* ... */}
@media (prefers-color-scheme: dark) { :root { --color-background: oklch(0.145 0.004 285.823); --color-foreground: oklch(0.985 0.001 285.823); /* ... */ }}Integración con next-themes
Un patrón común con Next.js y next-themes:
import { ThemeProvider } from "next-themes";
export default function RootLayout({ children }) { return ( <html suppressHydrationWarning> <body> <ThemeProvider attribute="class" defaultTheme="system"> {children} </ThemeProvider> </body> </html> );}@theme { --color-background: oklch(1 0 0); --color-foreground: oklch(0.145 0.004 285.823); --color-primary: oklch(0.205 0.006 285.885); --color-primary-foreground: oklch(0.985 0.001 285.823); /* ... all light tokens */}
.dark { --color-background: oklch(0.145 0.004 285.823); --color-foreground: oklch(0.985 0.001 285.823); --color-primary: oklch(0.985 0.001 285.823); --color-primary-foreground: oklch(0.205 0.006 285.885); /* ... all dark tokens */}El selector recogerá automáticamente los valores de token correctos a medida que cambia el tema.
Punto de Resalte en Modo Oscuro
El punto de resalte usa after:bg-amber-500 dark:after:bg-amber-400 (un color concreto de Tailwind, no un token) para asegurar una buena visibilidad en ambos modos. Este es el único color no semántico en el componente. Si necesitas cambiarlo, usa la API de Componentes Compuestos con un render personalizado para Day:
<DatePicker.Day date={date}> {(props) => ( <button /* ... */> {props.day} {props.isHighlighted && ( <span className="absolute bottom-0.5 w-1 h-1 rounded-full bg-emerald-500 dark:bg-emerald-400" /> )} </button> )}</DatePicker.Day>Forzar un Modo Específico
Para forzar el modo claro u oscuro independientemente de la preferencia del sistema, establece el tema explícitamente:
{ /* Always light */}<div data-theme="light"> <DatePicker value={value} onChange={setValue} /></div>;
{ /* Always dark */}<div data-theme="dark"> <DatePicker value={value} onChange={setValue} /></div>;