Theming
Getting StartedSistema de tokens semánticos con CSS custom properties, colores OKLCH y soporte completo para dark mode.
Sistema de tokens
KoreUI usa un sistema de design tokens basado en CSS custom properties con el prefijo --kore-*. Estos tokens definen colores, radios y animaciones que todos los componentes consumen de forma consistente.
Los tokens se definen en kore-theme.css y se registran en Tailwind v4 usando la directiva @theme inline, lo que genera clases utilitarias automáticamente (ej: bg-kore-primary, text-kore-fg, rounded-kore-md).
@theme inline {
--color-kore-primary: var(--kore-primary);
--color-kore-primary-fg: var(--kore-primary-fg);
--color-kore-secondary: var(--kore-secondary);
--color-kore-secondary-fg: var(--kore-secondary-fg);
--color-kore-bg: var(--kore-bg);
--color-kore-fg: var(--kore-fg);
--color-kore-surface: var(--kore-surface);
--color-kore-border: var(--kore-border);
--radius-kore-sm: var(--kore-radius-sm);
--radius-kore-md: var(--kore-radius-md);
--radius-kore-lg: var(--kore-radius-lg);
--radius-kore-xl: var(--kore-radius-xl);
/* ... más tokens */
}@theme inline {
--color-kore-primary: var(--kore-primary);
--color-kore-primary-fg: var(--kore-primary-fg);
--color-kore-secondary: var(--kore-secondary);
--color-kore-secondary-fg: var(--kore-secondary-fg);
--color-kore-bg: var(--kore-bg);
--color-kore-fg: var(--kore-fg);
--color-kore-surface: var(--kore-surface);
--color-kore-border: var(--kore-border);
--radius-kore-sm: var(--kore-radius-sm);
--radius-kore-md: var(--kore-radius-md);
--radius-kore-lg: var(--kore-radius-lg);
--radius-kore-xl: var(--kore-radius-xl);
/* ... más tokens */
}Colores OKLCH
Todos los colores usan el espacio de color OKLCH para mejor interpolación perceptual y consistencia visual.
OKLCH (Lightness, Chroma, Hue) ofrece ventajas sobre HSL y HEX: los colores con la misma luminosidad percibida realmente se ven igual de brillantes, y las transiciones entre colores son más suaves y naturales.
/* oklch(luminosidad crominancia tono) */
--kore-primary: oklch(0.55 0.25 250); /* Azul vibrante */
--kore-destructive: oklch(0.58 0.25 27); /* Rojo */
--kore-success: oklch(0.62 0.19 145); /* Verde */
--kore-warning: oklch(0.75 0.18 85); /* Amarillo/naranja *//* oklch(luminosidad crominancia tono) */
--kore-primary: oklch(0.55 0.25 250); /* Azul vibrante */
--kore-destructive: oklch(0.58 0.25 27); /* Rojo */
--kore-success: oklch(0.62 0.19 145); /* Verde */
--kore-warning: oklch(0.75 0.18 85); /* Amarillo/naranja */Ventaja: Al usar OKLCH, puedes cambiar solo el tono (hue) para obtener un color diferente manteniendo la misma luminosidad y saturación percibida. Esto facilita crear paletas consistentes.
Light y Dark mode
KoreUI soporta light mode, dark mode y modo sistema. Los tokens se redefinen automáticamente cuando el tema cambia.
El dark mode se activa mediante la clase .dark o el atributo [data-theme="dark"] en el elemento <html>. Los componentes no necesitan clases condicionales: el mismo token produce el color correcto en ambos temas.
@layer base {
/* --- Light mode (default) --- */
:root {
--kore-bg: oklch(1 0 0); /* Blanco */
--kore-fg: oklch(0.15 0 0); /* Casi negro */
--kore-primary: oklch(0.55 0.25 250);
--kore-surface: oklch(1 0 0);
--kore-border: oklch(0.92 0 0);
}
/* --- Dark mode --- */
.dark, [data-theme="dark"] {
--kore-bg: oklch(0.13 0 0); /* Casi negro */
--kore-fg: oklch(0.93 0 0); /* Casi blanco */
--kore-primary: oklch(0.70 0.20 250);
--kore-surface: oklch(0.17 0 0);
--kore-border: oklch(0.25 0 0);
}
}@layer base {
/* --- Light mode (default) --- */
:root {
--kore-bg: oklch(1 0 0); /* Blanco */
--kore-fg: oklch(0.15 0 0); /* Casi negro */
--kore-primary: oklch(0.55 0.25 250);
--kore-surface: oklch(1 0 0);
--kore-border: oklch(0.92 0 0);
}
/* --- Dark mode --- */
.dark, [data-theme="dark"] {
--kore-bg: oklch(0.13 0 0); /* Casi negro */
--kore-fg: oklch(0.93 0 0); /* Casi blanco */
--kore-primary: oklch(0.70 0.20 250);
--kore-surface: oklch(0.17 0 0);
--kore-border: oklch(0.25 0 0);
}
}Tokens de color
Los colores semánticos disponibles y su propósito. Cada color tiene una variante -fg para texto sobre ese color.
| Token | Light | Dark | Uso |
|---|---|---|---|
--kore-primary |
oklch(0.55 0.25 250) |
oklch(0.70 0.20 250) |
Color principal, acciones primarias |
--kore-secondary |
oklch(0.97 0.01 260) |
oklch(0.25 0.01 260) |
Acciones secundarias, fondos alternos |
--kore-accent |
oklch(0.92 0.01 260) |
oklch(0.30 0.01 260) |
Acentos, highlights |
--kore-destructive |
oklch(0.58 0.25 27) |
oklch(0.55 0.25 27) |
Eliminar, errores, acciones peligrosas |
--kore-success |
oklch(0.62 0.19 145) |
oklch(0.58 0.19 145) |
Confirmaciones, operaciones exitosas |
--kore-warning |
oklch(0.75 0.18 85) |
oklch(0.70 0.18 85) |
Advertencias, precaución |
--kore-info |
oklch(0.62 0.15 250) |
oklch(0.58 0.15 250) |
Información, tooltips, notas |
Cada color semántico tiene una variante -fg (ej: --kore-primary-fg) que define el color de texto ideal para usarse sobre ese fondo.
Tokens de superficie
Tokens para fondos, texto, bordes y estados interactivos de la interfaz.
| Token | Clase Tailwind | Descripción |
|---|---|---|
--kore-bg |
bg-kore-bg |
Fondo principal de la página |
--kore-fg |
text-kore-fg |
Color de texto principal |
--kore-surface |
bg-kore-surface |
Fondo de tarjetas, modales, paneles |
--kore-surface-fg |
text-kore-surface-fg |
Texto sobre superficies |
--kore-muted |
bg-kore-muted |
Fondo de elementos secundarios, hovers |
--kore-muted-fg |
text-kore-muted-fg |
Texto secundario, placeholders |
--kore-border |
border-kore-border |
Bordes y separadores |
--kore-input |
border-kore-input |
Borde de inputs de formulario |
--kore-ring |
ring-kore-ring |
Anillo de foco (focus ring) |
Tokens de radio
Radios de borde (border-radius) para mantener consistencia visual en toda la interfaz.
| Token | Valor | Clase Tailwind | Uso |
|---|---|---|---|
--kore-radius-sm |
0.25rem |
rounded-kore-sm |
Badges, chips, elementos pequenos |
--kore-radius-md |
0.375rem |
rounded-kore-md |
Inputs, botones, selects |
--kore-radius-lg |
0.5rem |
rounded-kore-lg |
Cards, dropdowns, modales |
--kore-radius-xl |
0.75rem |
rounded-kore-xl |
Contenedores grandes, tooltips |
Animaciones
KoreUI incluye una animacion spring personalizada y soporte para prefers-reduced-motion.
:root {
--kore-spring-easing: linear(...); /* Curva spring realista */
--kore-spring-duration: 500ms; /* Duración de la animación */
}
/* Reducción automática de movimiento */
@media (prefers-reduced-motion: reduce) {
:root {
--kore-spring-easing: ease;
--kore-spring-duration: 0ms;
}
}:root {
--kore-spring-easing: linear(...); /* Curva spring realista */
--kore-spring-duration: 500ms; /* Duración de la animación */
}
/* Reducción automática de movimiento */
@media (prefers-reduced-motion: reduce) {
:root {
--kore-spring-easing: ease;
--kore-spring-duration: 0ms;
}
}La animación spring se usa en toasts, overlays y transiciones. Cuando el usuario tiene activada la preferencia de movimiento reducido, las animaciones se desactivan automáticamente.
Uso en Tailwind v4
Los tokens se consumen directamente como clases Tailwind gracias a @theme inline.
<!-- Fondos -->
<div class="bg-kore-bg">Fondo principal</div>
<div class="bg-kore-surface">Fondo de tarjeta</div>
<div class="bg-kore-primary">Fondo primario</div>
<div class="bg-kore-muted">Fondo secundario/hover</div>
<!-- Textos -->
<p class="text-kore-fg">Texto principal</p>
<p class="text-kore-muted-fg">Texto secundario</p>
<span class="text-kore-primary">Texto de acento</span>
<!-- Bordes -->
<div class="border border-kore-border">Con borde</div>
<input class="border-kore-input focus:ring-kore-ring" />
<!-- Border radius -->
<div class="rounded-kore-md">Radio medio</div>
<div class="rounded-kore-lg">Radio grande</div>
<!-- Opacidad con tokens -->
<div class="bg-kore-primary/10">Fondo con 10% de opacidad</div>
<div class="border-kore-info/30">Borde translúcido</div><!-- Fondos -->
<div class="bg-kore-bg">Fondo principal</div>
<div class="bg-kore-surface">Fondo de tarjeta</div>
<div class="bg-kore-primary">Fondo primario</div>
<div class="bg-kore-muted">Fondo secundario/hover</div>
<!-- Textos -->
<p class="text-kore-fg">Texto principal</p>
<p class="text-kore-muted-fg">Texto secundario</p>
<span class="text-kore-primary">Texto de acento</span>
<!-- Bordes -->
<div class="border border-kore-border">Con borde</div>
<input class="border-kore-input focus:ring-kore-ring" />
<!-- Border radius -->
<div class="rounded-kore-md">Radio medio</div>
<div class="rounded-kore-lg">Radio grande</div>
<!-- Opacidad con tokens -->
<div class="bg-kore-primary/10">Fondo con 10% de opacidad</div>
<div class="border-kore-info/30">Borde translúcido</div>Personalizar colores
Puedes sobrescribir cualquier token redefiniendo las CSS custom properties en tu CSS.
@import 'tailwindcss';
@import '../../vendor/kore-ui/kore-ui/resources/css/kore-theme.css';
/* Sobrescribir el color primario */
@layer base {
:root {
--kore-primary: oklch(0.60 0.20 160); /* Verde esmeralda */
--kore-primary-fg: oklch(0.98 0 0); /* Blanco */
--kore-ring: oklch(0.60 0.20 160); /* Ring del mismo color */
}
.dark, [data-theme="dark"] {
--kore-primary: oklch(0.70 0.18 160); /* Verde más claro en dark */
--kore-primary-fg: oklch(0.15 0 0); /* Negro */
--kore-ring: oklch(0.70 0.18 160);
}
}@import 'tailwindcss';
@import '../../vendor/kore-ui/kore-ui/resources/css/kore-theme.css';
/* Sobrescribir el color primario */
@layer base {
:root {
--kore-primary: oklch(0.60 0.20 160); /* Verde esmeralda */
--kore-primary-fg: oklch(0.98 0 0); /* Blanco */
--kore-ring: oklch(0.60 0.20 160); /* Ring del mismo color */
}
.dark, [data-theme="dark"] {
--kore-primary: oklch(0.70 0.18 160); /* Verde más claro en dark */
--kore-primary-fg: oklch(0.15 0 0); /* Negro */
--kore-ring: oklch(0.70 0.18 160);
}
}Importante: Siempre define las variantes para :root (light) y .dark (dark) al sobrescribir tokens. Si solo defines uno, el otro tema usará los valores originales.
@layer base {
:root {
--kore-radius-sm: 0.125rem; /* Más cuadrado */
--kore-radius-md: 0.25rem;
--kore-radius-lg: 0.375rem;
--kore-radius-xl: 0.5rem;
}
}@layer base {
:root {
--kore-radius-sm: 0.125rem; /* Más cuadrado */
--kore-radius-md: 0.25rem;
--kore-radius-lg: 0.375rem;
--kore-radius-xl: 0.5rem;
}
}Anti-FOUC
El script @koreThemeScript previene el flash de tema incorrecto aplicando el tema antes del primer render.
<head>
@koreThemeScript {{-- ANTES de CSS y JS --}}
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head><head>
@koreThemeScript {{-- ANTES de CSS y JS --}}
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
Este script inline (~200 bytes) lee localStorage('kore-theme') y aplica la clase .dark y el atributo data-theme de forma síncrona antes de que el navegador pinte. Esto evita el parpadeo de tema incorrecto al cargar la página.
wire:navigate: El Alpine store se encarga de re-aplicar el tema después de cada navegación con wire:navigate de Livewire 4, registrando un listener en livewire:navigated.