Theming y textos
Paletas integradas, tonos de superficie, modo oscuro dirigido por clase y reemplazo de cada texto integrado para i18n.
Theming
// paleta integrada por lista
defineListConfig({ colorTheme: 'teal', /* … */ })
// default global
<ListKitProvider theme="teal">…</ListKitProvider>
// tema personalizado (colores de marca) — pasa un objeto ThemeClasses donde se acepta un tema
const brand: ThemeClasses = {
primaryBg: 'bg-[#121c38]',
primaryText: 'text-white',
focusRing: 'focus:ring-indigo-500',
focusBorder: 'focus:border-indigo-500',
/* … */
}
defineListConfig({ colorTheme: brand, /* … */ })Tones de tabla y cards
colorTheme maneja los acentos; tones maneja el chrome neutro — header de
la tabla, divisores, hover/selección de filas y el panel alrededor de la tabla
y de las cards default. Elige un preset integrado ('gray' es el default,
'contrast' invierte el header) o pasa un objeto SurfaceTones completo de
clases Tailwind. Los dos ejes componen: colorTheme: 'teal', tones: 'slate'.
// preset: 'gray' | 'slate' | 'zinc' | 'contrast'
defineListConfig({ tones: 'slate' /* … */ })
// custom — todo background opaco: las celdas pinned heredan el de la fila
defineListConfig({
tones: {
container: 'border-indigo-100 bg-white shadow-sm',
headerBg: 'bg-indigo-50',
headerText: 'text-indigo-700',
headerDivider: 'border-indigo-200',
rowBg: 'bg-white',
rowHover: 'hover:bg-indigo-50',
rowSelected: 'bg-indigo-100 hover:bg-indigo-100',
divider: 'divide-indigo-100',
},
/* … */
})La primitiva Table acepta el mismo valor como prop tones para uso suelto,
y getSurfaceTones resuelve un preset si necesitas las clases directamente.
Dark mode
Cada componente trae variantes dark: aditivas, activadas por una clase
.dark en un ancestro (normalmente <html>) — no por prefers-color-scheme —
para que tu app controle el toggle. listkit/tailwind.css registra
la variante por ti:
@custom-variant dark (&:where(.dark, .dark *));Con importar ese archivo basta. Sin él, Tailwind v4 lee dark: como
prefers-color-scheme, y una app sin modo oscuro renderiza sus listas en
oscuro para todo lector cuyo SO lo esté — con el resto de la página intacta.
Haz document.documentElement.classList.toggle('dark') y toda lista — tabla,
tarjetas, menús, filtros, diálogos, skeletons — lo sigue. Las paletas
integradas traen acentos dark; un ThemeClasses propio puede agregar sus
clases dark: dentro de cada campo. El render claro no cambia cuando la clase
no está.
Labels (i18n)
Los controles que un icono describe por sí solo (toggle de vista, botón de
filtros, conteo de resultados) son solo-icono, así que se leen igual en
cualquier idioma; sus nombres viven en aria-label/title. Todo el resto de
los textos integrados sale de un objeto labels que por defecto está en
inglés — sobreescríbelo para toda la app en el provider, o por lista con
config.labels.
Camino más corto — DEFAULT_LABELS (inglés) y ES_LABELS (español) cubren los
casos comunes en una línea (encima puedes sobreescribir claves sueltas):
import { ListKitProvider, ES_LABELS } from 'listkit'
// toda la app en español (el inglés es el default, así que no necesita prop)
;<ListKitProvider labels={ES_LABELS}>…</ListKitProvider>O elige los textos a mano:
// para toda la app (el idioma de la app)
;<ListKitProvider
labels={{
tableView: 'Vista tabla',
cardsView: 'Vista tarjetas',
filters: 'Filtros',
applyFilters: 'Aplicar',
clearFilters: 'Limpiar',
empty: 'Sin resultados',
yes: 'Sí',
no: 'No',
results: n => `${n} resultado${n === 1 ? '' : 's'}`,
}}
>
…
</ListKitProvider>
// o por lista (gana sobre el provider)
defineListConfig({ labels: { empty: 'Sin pedidos' } /* … */ })NextListView acepta la misma prop labels (y theme) y la reenvía a su
provider interno: <NextListView labels={ES_LABELS} config={…} adapter={…} />.
Orden de resolución: config.labels → labels del provider → DEFAULT_LABELS.
Las props por elemento que ya existen siguen ganando donde aplican
(config.emptyMessage, config.filtersTitle, el trueLabel/falseLabel de un
filtro). Consulta ListLabels para la lista completa de claves.