El contrato de estilos
Cada parte pública acepta directamente tu className, style, ref, manejadores de eventos, props nativas y atributos data-*. No hay props paralelas como contentClassName o triggerClassName.
uiify controla los atributos de identidad y estado. Sirven como puntos de estilo: cambia el estado mediante props o el comportamiento nativo de HTML, nunca escribiendo data-state. El espacio de nombres --uiify-* se reserva para geometría, animación y valores de cada instancia.
<Popover.Root>
<Popover.Trigger className="toolbar-trigger">Open</Popover.Trigger>
<Popover.Content className="toolbar-popover" data-layout="compact">
Actions
</Popover.Content>
</Popover.Root>Nombres
| Punto de estilo | Propósito | Ejemplo |
|---|---|---|
| Marcadores de identidad | Identidad estable del componente, controlada por uiify | data-uiify-popover |
| Marcadores de anatomía | Parte compuesta pública, controlada por uiify | data-part="content" |
| Atributos de estado | Reflejo del estado de solo lectura para selectores | data-state="open" |
| Propiedades personalizadas | Geometría dinámica y valores de cada instancia | --uiify-anchor-x |
Cada raíz con estado tiene un marcador data-uiify-<component> cuya presencia la identifica. Cada parte compuesta tiene un valor data-part en kebab-case, como trigger, content, item o label. Las props del consumidor no pueden reemplazar estos valores.
CSS y Tailwind
[data-uiify-popover][data-part="content"] {
min-inline-size: 12rem;
}
[data-uiify-popover][data-part="content"][data-state="open"] {
opacity: 1;
}
/* Tailwind uses the same attributes. */
<div className="data-[state=open]:opacity-100" />Polimorfismo
as y render reemplazan el elemento renderizado. Un renderizador personalizado debe pasar las props y la ref que recibe al elemento del DOM; de lo contrario, los marcadores, el estado y los estilos dejan de funcionar.
behavior.css es obligatorio
Esta hoja de estilos contiene las reglas que hacen funcionar el estado: posición de ventanas emergentes, tamaño de ::details-content, propagación con :has(), ubicación de inputs ocultos y transiciones con @starting-style. No contiene colores, fuentes ni espaciado.
import "@gunkin/uiify/components/behavior.css";Sin ella, los componentes se renderizan, pero su estado no funciona. Impórtala una vez, en cualquier lugar de tu aplicación.
El estado es un atributo, no una clase
Los componentes exponen el estado como atributos data-* en el elemento que lo gestiona, para que CSS pueda seleccionarlo sin JavaScript ni nombres de clase. Cada página de componente enumera los atributos que genera.
.my-trigger[data-state="open"] { … }
.my-item[data-disabled] { … }
/* Native state works the same way, because the state IS native */
.my-panel:popover-open { … }
details[open] > summary { … }Las variantes también son atributos data-*, no consultas de estilo de contenedor, porque un contenedor no puede consultarse a sí mismo.
Valores en línea, reglas en una hoja de estilos
Los valores de cada instancia llegan como propiedades personalizadas en línea; todas las reglas residen en una hoja de estilos estática. Los estilos en línea no pueden expresar pseudoclases, pseudoelementos, consultas de contenedor ni @starting-style, y el modelo de estado depende de todos ellos.
Las propiedades en línea llegan con el HTML en streaming sin discrepancias de hidratación, y la hoja de estilos se analiza una sola vez y se guarda en caché. CSS-in-JS, en cambio, inyecta fragmentos <style> en cada límite y no los reutiliza entre solicitudes.
Tres formas de aplicar estilos
Tu propio CSS. Selecciona el elemento y sus atributos data-*; no hay estilos predeterminados que debas reemplazar.
Tailwind. Los mismos atributos funcionan como variantes, por ejemplo data-[state=open]:rotate-180. Las vistas previas del sitio cambian a la apariencia de Tailwind desde la opción Estilo del encabezado.
@gunkin/uiify/styles. Una capa opcional de CSS con escalas de tokens OKLCH, temas claro y oscuro, y una apariencia para cada componente: un punto de partida, no un requisito.
import "@gunkin/uiify/styles/reset";
import "@gunkin/uiify/styles";Orden de la cascada
Todo lo que incluye uiify se encuentra en una capa con nombre por debajo de la tuya:
@layer ui.reset, ui.behavior, ui.tokens, ui.theme, app;Tu capa siempre tiene prioridad: las personalizaciones no necesitan !important ni trucos de especificidad, y se mantienen aunque se reorganice el código de la biblioteca.
Cada página de componente enumera sus atributos y variables CSS, con CSS listo para copiar y pegar para ambas apariencias.