⏱️ Lectura: 13 min
Phoenix LiveView 1.2 llegó el 10 de junio de 2026 con una característica que muchos desarrolladores de Elixir venían esperando: CSS colocado dentro de las plantillas HEEx. Ahora podés escribir los estilos justo al lado del componente que los usa, sin saltar a un archivo aparte.
📑 En este artículo
Pero hay un giro interesante. El equipo construyó toda la infraestructura necesaria para hacer scoping de CSS y, aun así, decidió no activarlo por defecto. En este artículo vemos qué trae Phoenix LiveView 1.2, cómo funciona el CSS colocado por dentro y por qué esa decisión tiene mucho sentido.
TL;DR
- Phoenix LiveView 1.2 se publicó el 10 de junio de 2026, anunciado por Steffen Deusch.
- Introduce CSS colocado en plantillas HEEx mediante
<style :type={Modulo.ColocatedCSS}>. - El CSS se extrae en tiempo de compilación a la carpeta
phoenix-colocateddentro de_build. - Usa la regla
@scopede CSS y un atributophx-rpara acotar los estilos a un componente. - El scoping NO viene activado por defecto:
@scopeaún no tiene buen soporte en navegadores en junio de 2026. - La compilación de HEEx se dividió en tokenización y parsing separados para soportar macro-componentes.
- Actualizar es tan simple como cambiar
{:phoenix_live_view, "~> 1.2.0"}enmix.exs.
Qué trae Phoenix LiveView 1.2
Phoenix LiveView 1.2 es una versión incremental sobre la rama 1.1, pero el cambio principal toca un punto sensible del desarrollo web: dónde viven los estilos. En la versión 1.1, el equipo había introducido los Colocated Hooks y el Colocated JavaScript, que permiten escribir hooks de JavaScript directamente dentro de cualquier plantilla HEEx. La versión 1.2 extiende ese mismo trabajo de base, hecho sobre Phoenix.LiveView.ColocatedJS, para que ahora también puedas colocar CSS dentro de HEEx.
La idea de fondo es simple y poderosa: si un componente define su estructura (HTML), su comportamiento (JS) y su apariencia (CSS) en el mismo lugar, el componente se vuelve autocontenido. No hay que cazar la hoja de estilos correcta en otra carpeta, ni adivinar qué clases globales lo afectan. Para quien viene de React con CSS Modules, styled-components o Vue con <style scoped>, el concepto va a sonar familiar; lo nuevo es cómo Phoenix LiveView 1.2 lo resuelve aprovechando que controla la compilación de HEEx a HTML.
CSS colocado: estilos junto al componente
El uso básico es directo. Dentro de tu plantilla HEEx agregás una etiqueta <style> con un atributo especial :type que apunta a un módulo de CSS colocado. Veamos un ejemplo de un componente de tabla:
def table(assigns) do
~H"""
<style :type={MyApp.ColocatedCSS}>
thead {
color: var(--brand);
}
tbody tr:hover {
background: #f5f5f5;
}
</style>
<table>...</table>
"""
end
Igual que con el JavaScript colocado, el atributo :type le dice a LiveView que extraiga el contenido de la etiqueta en tiempo de compilación. Ese CSS no se queda inline en el HTML: se vuelca a una carpeta especial llamada phoenix-colocated dentro de tu directorio _build. Desde ahí lo recoge tu bundler habitual —normalmente Tailwind o Esbuild— y lo procesa como parte de tu pipeline de CSS de siempre. En otras palabras, no hay magia en tiempo de ejecución ni un sistema de estilos paralelo: todo termina pasando por las mismas herramientas que ya usás.
💭 Clave: el CSS colocado no agrega peso en runtime. Se extrae al compilar y entra a tu bundler estándar, así que el resultado final es el mismo CSS optimizado que ya generabas.
Hasta acá la parte fácil. El problema real aparece cuando querés que esos estilos no se escapen y afecten a otros elementos de la página que vienen de componentes distintos. Eso es el scoping, y es donde Phoenix LiveView 1.2 hace algo elegante.
La regla @scope y el atributo phx-r
El CSS moderno trae una regla relativamente nueva, @scope, que permite limitar el alcance de un conjunto de reglas a una porción concreta del árbol del DOM. Su forma general es así:
@scope (raiz del scope) to (limite del scope) {
/* reglas que solo aplican dentro de ese rango */
}
La regla acepta un selector raíz y un selector límite opcional. Si pudiéramos anotar el HTML renderizado con un atributo único que identifique la raíz de una plantilla y otro que marque dónde termina, podríamos escribir reglas que apliquen solo a esa plantilla. Y como LiveView controla cómo se compila HEEx a HTML, puede hacer exactamente eso.
Para lograrlo, LiveView marca los elementos más externos de cada plantilla con un atributo especial phx-r, que sirve como selector límite en la regla @scope. Cuando un componente usa CSS colocado con scope, sus elementos raíz reciben además un atributo único del tipo phx-css-*. Hay un detalle fino con los slots: el contenido que pasa el componente que llama (por ejemplo, un <p> dentro de un slot) no pertenece a la plantilla del componente sino a quien lo invoca, así que también se considera una raíz y recibe su propio phx-r. Esto evita que los estilos del componente se filtren hacia el contenido que el usuario inyecta.
Con esas anotaciones, el CSS scoped se ve así:
@scope ([phx-css-foo]) to ([phx-r]) {
p {
font-weight: bold;
}
}
Con esa regla, solo los <p> que pertenecen a la plantilla del componente se renderizan en negrita; cualquier otro <p> de la página queda intacto. LiveView no inyecta el atributo phx-r de forma automática: es opt-in mediante una nueva configuración de compilación.
config :phoenix_live_view,
# atributo que se pone en todos los tags raiz.
# Lo usa Phoenix.LiveView.ColocatedCSS.
root_tag_attribute: "phx-r"
Por qué no activan el scoping por defecto
Acá viene la decisión que sorprende. Después de todo ese esfuerzo para hacer posible el CSS colocado y el scoping, Phoenix LiveView 1.2 no envía el scoping activado por defecto. La razón es honesta y pragmática: la regla @scope todavía no tiene buen soporte en todos los navegadores al momento de escribir esto, en junio de 2026. Activarla por defecto rompería estilos en una parte de los usuarios finales, algo inaceptable para un framework que prioriza la estabilidad.
En lugar de imponer una solución que aún no es universal, el equipo expone un @behaviour que podés implementar para hacer scoping con la estrategia que prefieras. Esto deja la puerta abierta a varias técnicas —desde @scope nativo hasta prefijos de clase generados o atributos de datos— sin atar el framework a una sola. Quien quiera ser early adopter de @scope tiene la implementación documentada y lista para copiar.
⚠️ Ojo: si activás el scoping con @scope hoy, verificá la compatibilidad con los navegadores de tu audiencia. En junio de 2026 el soporte todavía es parcial, sobre todo en versiones antiguas.
Esta filosofía —dar la herramienta sin forzar la opinión— es muy del estilo de Phoenix. El framework prefiere que el desarrollador decida cuándo el soporte de una feature web es suficiente para su caso, en vez de tomar esa decisión por todos.
Cómo cambió la compilación de HEEx
Implementar el CSS colocado obligó al equipo a revisar cómo se compilan las plantillas HEEx. El resumen es que dividieron la compilación en dos pasos separados: una etapa de tokenización y otra de parsing. Esa separación les permitió manejar los macro-componentes —el CSS y el JS colocados— sin volver más complejo el resto del proceso de compilación. Como bonus, pudieron reutilizar código que antes estaba duplicado entre la compilación de plantillas y el formateo.
graph LR
A["Plantilla HEEx"] --> B["Tokenizacion"]
B --> C["Parsing"]
C --> D["Extraccion de macro-componentes"]
D --> E["Carpeta phoenix-colocated"]
E --> F["Bundler (Tailwind / Esbuild)"]
Este tipo de refactor interno rara vez es visible para quien usa el framework, pero es la clase de inversión que paga dividendos a largo plazo: una arquitectura de compilación más limpia facilita agregar nuevas features colocadas en el futuro sin acumular deuda técnica. El equipo publicó además un análisis técnico aparte para quien quiera entrar en el detalle de este rediseño.
Contexto e historia
Phoenix es el framework web por excelencia del ecosistema Elixir, y LiveView es su pieza más distintiva: permite construir interfaces interactivas en tiempo real renderizadas en el servidor, con muy poco JavaScript escrito a mano. La comunicación entre el servidor y el navegador va por WebSocket, y LiveView envía solo los diffs mínimos del HTML cuando el estado cambia. Esto le dio a Elixir una ventaja particular para apps reactivas sin el peso de un framework de frontend completo.
La línea de trabajo de la “colocación” —tener HTML, JS y CSS juntos— viene madurando hace varias versiones. Primero fueron los hooks y el JavaScript colocados en la 1.1, y ahora el CSS en la 1.2. Es una respuesta directa a una tensión clásica del desarrollo web: la separación de responsabilidades por tipo de archivo (todo el CSS en un lado, todo el JS en otro) suena ordenada en teoría, pero en la práctica obliga a saltar entre archivos para entender un solo componente. La tendencia de los últimos años, vista en React, Svelte y Vue, fue agrupar por componente en lugar de por tipo de archivo. Phoenix LiveView 1.2 trae esa misma comodidad al mundo de HEEx, pero con una diferencia técnica importante: la extracción ocurre en compilación y se apoya en estándares CSS nativos, no en una capa de runtime propietaria.
Cómo actualizar
Pasar de LiveView 1.1 a 1.2 es trivial. Solo tenés que actualizar el requisito de versión en tu archivo mix.exs y volver a bajar las dependencias:
# En mix.exs
{:phoenix_live_view, "~> 1.2.0"}
Los comandos de Mix son idénticos en los tres sistemas operativos. Una vez editado mix.exs, ejecutá:
# Windows (PowerShell o CMD), macOS y Linux: mismo comando
mix deps.get
# O para forzar la actualización de ese paquete puntual:
mix deps.update phoenix_live_view
💡 Tip: si usás Elixir víaasdfomiseen macOS/Linux, o el instalador oficial en Windows, no necesitás nada extra:mixya viene con la toolchain. El CSS colocado no requiere cambios en tu bundler más allá de que Tailwind/Esbuild lean la carpeta generada.
Entre las mejoras menores que también trae la 1.2 está la posibilidad de implementar un Phoenix.LiveView.HTMLFormatter.TagFormatter para formatear etiquetas <script> y <style> en HEEx con la herramienta que prefieras —la documentación muestra un ejemplo con prettier—, y que las estructuras Phoenix.LiveView.JS ahora se codifican automáticamente al enviarse.
Impacto para desarrolladores en LATAM
Para los equipos hispanohablantes que ya apostaron por Elixir y Phoenix, esta versión reduce una fricción cotidiana. El CSS colocado significa que un componente compartido —pensá en un design system interno de una startup o una agencia— puede empaquetar su estructura, comportamiento y estilo en un solo módulo, más fácil de versionar, revisar y reutilizar entre proyectos. Eso baja el costo de mantener consistencia visual cuando varios desarrolladores tocan el mismo código.
El consejo práctico para nuestra región es el mismo que para todos: aprovechá el CSS colocado desde ya, porque la extracción en compilación es estable y no depende del navegador. Pero respecto al scoping con @scope, medí primero qué navegadores usa tu base de usuarios. En mercados donde todavía hay dispositivos viejos o navegadores desactualizados, activar @scope hoy puede traer sorpresas; en cambio, una estrategia de scoping basada en clases generadas mediante el @behaviour que provee LiveView te da compatibilidad amplia sin renunciar al aislamiento.
Qué sigue
El camino parece claro: a medida que el soporte de @scope se generalice en los navegadores, es razonable esperar que el scoping nativo pase de opt-in a una recomendación más fuerte, e incluso al comportamiento por defecto en una versión futura. Mientras tanto, la infraestructura ya está lista y el @behaviour permite que cada equipo elija su momento. La separación de la compilación de HEEx en tokenización y parsing, además, deja el terreno preparado para futuras features colocadas sin tener que volver a tocar el núcleo del compilador.
Para seguir el avance, lo mejor es vigilar el repositorio oficial de phoenix_live_view en GitHub y el blog de Phoenix, donde el equipo suele publicar análisis técnicos detallados de cada cambio relevante.
📖 Resumen en Telegram: Ver resumen
Preguntas frecuentes
¿Qué es el CSS colocado en Phoenix LiveView 1.2?
Es la posibilidad de escribir bloques <style :type={Modulo.ColocatedCSS}> directamente dentro de una plantilla HEEx. LiveView extrae ese CSS en tiempo de compilación a la carpeta phoenix-colocated y tu bundler (Tailwind o Esbuild) lo procesa como parte del pipeline normal.
¿El scoping de CSS viene activado por defecto?
No. Aunque Phoenix LiveView 1.2 incluye toda la infraestructura para hacer scoping con la regla @scope y el atributo phx-r, no lo activa por defecto porque @scope aún no tiene buen soporte en todos los navegadores a junio de 2026. Se expone un @behaviour para implementar la estrategia que prefieras.
¿Cómo actualizo de LiveView 1.1 a 1.2?
Cambiá la dependencia a {:phoenix_live_view, "~> 1.2.0"} en mix.exs y ejecutá mix deps.get. El comando es el mismo en Windows, macOS y Linux.
¿Para qué sirve el atributo phx-r?
Es un atributo que LiveView agrega a los elementos raíz de cada plantilla y que sirve como selector límite en la regla @scope. Combinado con un atributo único phx-css-*, permite que los estilos de un componente apliquen solo dentro de ese componente y no se filtren al resto de la página.
¿Necesito cambiar mi bundler para usar CSS colocado?
No hace falta un bundler nuevo. El CSS extraído se deposita en una carpeta dentro de _build que tu Tailwind o Esbuild existente puede leer como parte de su flujo habitual. No hay procesamiento en tiempo de ejecución.
¿Por qué cambiaron la compilación de HEEx?
Para soportar los macro-componentes (CSS y JS colocados) sin complicar el resto del compilador, dividieron la compilación en dos pasos: tokenización y parsing. Esto también permitió reutilizar código que antes estaba duplicado entre la compilación de plantillas y el formateo.
Referencias
- Phoenix Blog — Anuncio oficial de Phoenix LiveView 1.2 (10 de junio de 2026).
- GitHub: phoenix_live_view — Repositorio oficial con código fuente, changelog e issues.
- HexDocs: Phoenix.LiveView — Documentación de la API, incluido el módulo ColocatedCSS.
- MDN: @scope — Referencia de la regla CSS @scope y su compatibilidad con navegadores.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
0 Comentarios