
VanillaCreamJS es una biblioteca de JavaScript que literalmente otorga “súperpoderes” a JavaScript puro, permitiendo capacidades modernas y potentes como la reactividad, sin necesidad de herramientas de compilación ni pasos de build.
Es una tecnología única porque:
- Aporta reactividad a JavaScript puro.
- Funciona con un rendimiento sobresaliente gracias a la ausencia de algoritmos de diffing o recálculo.
- Ofrece herramientas potentes con una API mínima e intuitiva.
- Ayuda a mejorar tu comprensión de JavaScript puro.
- Se puede integrar con cualquier stack de backend sin fricciones.
- Aumenta la productividad del desarrollador en proyectos de tamaño pequeño a mediano.
- Combina lo mejor de herramientas como HTMX, Vue y Alpine.
- Su nombre refleja su objetivo: refinar JavaScript puro y elevarlo, sin alejarse demasiado de sus raíces.
VanillaCreamJS es creado y mantenido por Riccardo Degni, un desarrollador web senior italiano. 👉 https://www.riccardodegni.com/projects/vanillacreamjs
📦 Instalación
Simplemente incluye VanillaCreamJS a través de un CDN:
HTML
<script src="https://cdn.jsdelivr.net/npm/vanillacream/dist/vanillacream.min.js"></script>
Lenguaje del código: HTML, XML (xml)
O, instálalo vía NPM:
Bash
npm install vanillacreamjs
💥 Súperpoderes para elementos del DOM
En el núcleo de VanillaCream se encuentra la función $
. A primera vista puede recordarte a jQuery, pero es un universo completamente diferente —y mucho más moderno— de funcionalidades.
Esta función devuelve un elemento (o un conjunto de elementos) con súperpoderes, incluyendo vinculación reactiva de estado:
HTML
<div id="app">
<div id="el"></div>
</div>
<script>
const [el, s] = $('#el', { counter: 10 })
el.text = () => s.counter
el.onClick(() => s.counter++)
</script>
Lenguaje del código: HTML, XML (xml)
Aquí, la función $
devuelve un elemento del DOM (en este caso el
) y un objeto de estado reactivo s
. Cada elemento potenciado por $
expone propiedades poderosas:
text
: establecer contenido de textohtml
: establecer contenido HTML internoclass
: alternar clases CSS dinámicamenteon
: agregar listeners de eventos (comoonClick
,onInput
, etc.)attr
: establecer atributos HTMLdata
: establecer atributosdata-*
Cuando asignas una función a una de estas propiedades, se vuelve reactiva, actualizando automáticamente el DOM cuando el estado cambia.
Ejemplo: alternar una clase CSS
HTML
<div id="app">
<div id="el">box</div>
</div>
<script>
const [el, s] = $('#el', { hl: true })
el.class.highlighted = () => s.hl
el.on.click(() => s.hl = !s.hl)
</script>
<style>
.highlighted { background-color: lightgreen; padding: 10px; }
</style>
Lenguaje del código: HTML, XML (xml)
Al hacer clic en el elemento se alterna el valor de s.hl
, lo que añade o elimina dinámicamente la clase highlighted
—sin manipulación manual del DOM.
⚙️ Reactividad múltiple con .set
También puedes aplicar múltiples propiedades reactivas a la vez usando .set
:
JavaScript
el.css.set({
color: 'blue',
backgroundColor: () => state.bg,
width: () => state.x + 'px'
})
el.class.set({
active: () => state.active,
box: () => state.counter >= 10,
otherClass: () => state.active && state.counter >= 10
})
el.attr.set({
title: () => `Title: ${state.title}`
})
el.data.set({
x: () => state.x * 10
})
Lenguaje del código: CSS (css)
Refs: Desestructuración poderosa
La función $.refs
acepta un elemento raíz y devuelve variables automáticamente enlazadas para cada ref del template, además de un objeto de estado reactivo compartido:
HTML
<div id="app">
<div ref="el"></div>
<button ref="btn">Actualizar estado</button>
</div>
<script>
const { el, btn, state } = $.refs('#app', { counter: 0, bg: 'lightblue', boxClass: false })
el.html = () => `Counter: ${state.counter}`
el.css.backgroundColor = () => state.bg
el.class.box = () => state.boxClass
btn.onClick(() => {
state.counter++
if (state.bg !== 'lightgreen') state.bg = 'lightgreen'
state.boxClass = !state.boxClass
})
</script>
Lenguaje del código: HTML, XML (xml)
Incluso puedes usar namespaces en tus refs para una desestructuración más organizada:
<button ref="btn.AZ">Ordenar A-Z</button>
<button ref="btn.ZA">Ordenar Z-A</button>
<button ref="btn.Random">Aleatorio</button>
<ul ref="el"></ul>
<script>
const { el, btn, state } = $.refs('#app', { /* ... */ })
</script>
Lenguaje del código: HTML, XML (xml)
🧠 Reactividad profunda
El motor reactivo de VanillaCream soporta tanto tipos primitivos como referencias (arrays, objetos, matrices). Puedes activar reactividad simplemente modificando elementos de un array o propiedades de un objeto, incluso usando métodos como push
, pop
o splice
.
HTML
<div id="app">
<div ref="box"></div>
Insertar fruta: <input ref="fruit">
<button ref="btn">Añadir fruta</button>
</div>
<script>
const { box, fruit, btn, state } = $.refs('#app', { fruits: ['apple', 'pear', 'kiwi'] })
box.text = () => 'Fruits: ' + state.fruits.join(', ')
btn.onClick(() => {
state.fruits.push(fruit.attr.value)
fruit.attr.value = ''
})
</script>
Lenguaje del código: HTML, XML (xml)
Aquí, actualizar el array actualiza automáticamente el DOM. No se necesitan hooks complejos ni lógica de renderizado —solo JavaScript puro.
Templates HTML reactivos
VanillaCream soporta expresiones reactivas directamente en tu HTML usando atributos x-
:
HTML
<div id="app">
<div x-text="`Counter: ${state.counter}`"></div>
<button x-on.click="() => state.counter++">Incrementar contador</button>
<div x-if="state.counter === 10">¡El contador es 10!</div>
</div>
<script>
const { state } = $.refs('#app', { counter: 0 })
</script>
Lenguaje del código: HTML, XML (xml)
Solicitudes AJAX simplificadas
VanillaCream ofrece control total sobre AJAX con una sintaxis muy simple:
JavaScript
el.post('https://jsonplaceholder.typicode.com/posts/', {
data: {
title: 'VanillaCream.js',
body: 'Best Vanilla JS framework',
userId: 1
}
})
Lenguaje del código: JavaScript (javascript)
🧩 Creación de componentes reutilizables con VanillaCream
Una de las funcionalidades más potentes es la capacidad de construir componentes reactivos reutilizables en JavaScript puro, sin render functions personalizadas, hooks ni virtual DOM:
JavaScript
const Counter = {
state: () => ({ count: 0 }),
template: `
<p ref="p"></p>
<button ref="btn">+</button>
`,
setup({ refs, state }) {
const {p, btn} = refs
p.text = () => `Count: ${state.count}`
btn.onClick(() => state.count++)
}
}
Lenguaje del código: JavaScript (javascript)
Para renderizar este componente en uno o varios lugares:
JavaScript
$('#counter1, #counter2').component(Counter)
Lenguaje del código: JavaScript (javascript)
Componentes con parámetros
Los componentes de VanillaCream también pueden recibir datos personalizados:
HTML
<div id="app">
<div ref="counter1"></div>
<div ref="counter2"></div>
</div>
<script>
const Counter = {
data: {start: 0},
state: () => ({ count: 0 }),
template: `<p ref="p"></p><button ref="btn">+</button>`,
setup({ refs, state, data }) {
state.count = data.start
refs.p.text = () => `Count: ${state.count}`
refs.btn.onClick(() => state.count++)
}
}
const {counter1, counter2} = $.refs('#app')
counter1.component(Counter, { data: {start: 5} })
counter2.component(Counter, { data: {start: 100} })
</script>
Lenguaje del código: HTML, XML (xml)
Propiedades computadas
VanillaCream permite derivar valores basados en otros estados reactivos:
HTML
<div id="app">
<div ref="box"></div>
<input ref="input" type="text">
</div>
<script>
const { box, input, state } = $.refs('#app', {
firstName: 'John',
lastName: 'Doe'
})
const fullName = () => `${state.firstName} ${state.lastName}`
box.text = () => `¡Hola, ${fullName()}!`
input.onInput(() => {
const [fn, ln] = input.attr.value.split(' ')
state.firstName = fn
state.lastName = ln ?? ''
})
</script>
Lenguaje del código: HTML, XML (xml)
Compatible con cualquier backend
Aunque VanillaCream soporta componentes, también puedes delegar el renderizado al backend. Se integra perfectamente con cualquier stack.
Por ejemplo, en Laravel podrías tener una vista Blade que proporcione datos desde la base de datos:
PHP
<div id="app">
<div ref="box"></div>
Insertar fruta: <input ref="fruit">
<button ref="btn">Añadir fruta</button>
</div>
<script>
const { box, fruit, btn, state } = $.refs('#app', {
fruits: @json($fruits)
})
box.text = () => 'Fruits: ' + state.fruits.join(', ')
btn.onClick(async () => {
const v = fruit.attr.value
await $.get('/my-backend/add-fruit', {
data: { fruit: v }
})
state.fruits.push(v)
fruit.attr.value = ''
})
</script>
Lenguaje del código: HTML, XML (xml)
🚀 ¿Listo para probar VanillaCream?
Ya sea que estés construyendo un prototipo rápido, mejorando una app existente o simplemente quieras redescubrir la alegría de escribir JavaScript reactivo limpio, VanillaCream.js ofrece una solución ligera y elegante, sin pasos de build.
👉 Documentación
🧪 Demos en vivo
🛠️ Playground
Pruébalo y experimenta el poder de la reactividad… ¡a la manera del vanilla JS!