Introducción a lit-html: Creando Interfaces Web Modernas y Eficientes
Descubre lit-html, la librería de Google para crear interfaces web ligeras y rápidas. Aprende a construir componentes dinámicos sin el peso de un framework completo.

¿Buscas una alternativa ligera a React o Vue?
¡lit-html te permite crear interfaces dinámicas con JavaScript vanilla!
¿Qué es lit-html?
lit-html es una librería de Google que permite crear interfaces web dinámicas usando JavaScript vanilla y template literals. Es la base del framework Lit, pero puedes usarla de forma independiente para crear componentes ligeros y eficientes.
Características principales:
- Ligero: Solo ~5KB minificado y gzipped
- Rápido: Renderizado eficiente con actualizaciones incrementales
- Moderno: Usa template literals nativos de JavaScript
- Interoperable: Funciona con cualquier librería o framework
- Sin build: No necesitas transpilación ni bundling
¿Por qué elegir lit-html?
Ventajas principales:
- Tamaño mínimo: Ideal para proyectos donde el tamaño importa
- Curva de aprendizaje suave: Si conoces JavaScript, ya sabes lit-html
- Sin dependencias: No necesitas un ecosistema completo
- Rendimiento: Actualizaciones eficientes solo donde cambia el DOM
- Flexibilidad: Se integra fácilmente con otras librerías
Casos de uso ideales:
- Micro-frontends
- Widgets ligeros
- Aplicaciones pequeñas a medianas
- Prototipos rápidos
- Componentes reutilizables
Instalación y configuración
1. Instalación básica
npm install lit-html
2. Importación en tu proyecto
import { html, render } from 'lit-html';
3. Configuración para desarrollo (opcional)
Si quieres usar ES modules en el navegador directamente:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import { html, render } from 'https://unpkg.com/lit-html@3.1.0/lit-html.js?module';
</script>
</head>
<body>
<div id="app"></div>
</body>
</html>
Conceptos fundamentales
1. Template literals con html
lit-html usa template literals marcados con la función html
:
import { html, render } from 'lit-html';
const template = html`
<h1>¡Hola, lit-html!</h1>
<p>Este es mi primer template dinámico</p>
`;
render(template, document.getElementById('app'));
2. Expresiones dinámicas
Puedes insertar JavaScript directamente en tus templates:
const nombre = 'María';
const edad = 25;
const template = html`
<div>
<h2>Perfil de ${nombre}</h2>
<p>Edad: ${edad} años</p>
<p>Es mayor de edad: ${edad >= 18 ? 'Sí' : 'No'}</p>
</div>
`;
render(template, document.getElementById('app'));
3. Atributos dinámicos
const url = 'https://ejemplo.com';
const clase = 'btn btn-primary';
const template = html`
<a href="${url}" class="${clase}">
Enlace dinámico
</a>
`;
Renderizado y actualizaciones
Renderizado inicial
import { html, render } from 'lit-html';
function miComponente(datos) {
return html`
<div class="card">
<h3>${datos.titulo}</h3>
<p>${datos.descripcion}</p>
</div>
`;
}
// Renderizado inicial
const datos = { titulo: 'Mi título', descripcion: 'Mi descripción' };
render(miComponente(datos), document.getElementById('app'));
Actualizaciones eficientes
lit-html solo actualiza las partes que cambian:
// Actualizar solo los datos
datos.titulo = 'Nuevo título';
render(miComponente(datos), document.getElementById('app'));
// Solo se actualiza el h3, no todo el componente
Directivas avanzadas
1. repeat()
- Listas eficientes
import { html, render } from 'lit-html';
import { repeat } from 'lit-html/directives/repeat.js';
const usuarios = [
{ id: 1, nombre: 'Ana' },
{ id: 2, nombre: 'Carlos' },
{ id: 3, nombre: 'Elena' }
];
const template = html`
<ul>
${repeat(usuarios, (usuario) => usuario.id, (usuario) => html`
<li>${usuario.nombre}</li>
`)}
</ul>
`;
2. when()
- Renderizado condicional
import { html, render } from 'lit-html';
import { when } from 'lit-html/directives/when.js';
const estaCargando = true;
const template = html`
${when(estaCargando,
() => html`<div>Cargando...</div>`,
() => html`<div>Contenido cargado</div>`
)}
`;
3. classMap()
- Clases dinámicas
import { html, render } from 'lit-html';
import { classMap } from 'lit-html/directives/class-map.js';
const clases = {
'btn': true,
'btn-primary': true,
'btn-disabled': false
};
const template = html`
<button class=${classMap(clases)}>
Botón dinámico
</button>
`;
Eventos y interactividad
Manejo de eventos
function miComponente() {
const handleClick = (e) => {
console.log('Botón clickeado!');
};
const handleInput = (e) => {
console.log('Valor:', e.target.value);
};
return html`
<div>
<button @click=${handleClick}>
Haz clic aquí
</button>
<input @input=${handleInput} placeholder="Escribe algo...">
</div>
`;
}
Estado local
let contador = 0;
function componenteContador() {
const incrementar = () => {
contador++;
render(componenteContador(), document.getElementById('app'));
};
return html`
<div>
<h3>Contador: ${contador}</h3>
<button @click=${incrementar}>Incrementar</button>
</div>
`;
}
Ejemplo práctico: Lista de tareas
import { html, render } from 'lit-html';
// Estado de la aplicación
let tareas = [
{ id: 1, texto: 'Aprender lit-html', completada: false },
{ id: 2, texto: 'Crear un proyecto', completada: true }
];
// Funciones de manejo
function agregarTarea() {
const input = document.getElementById('nueva-tarea');
const texto = input.value.trim();
if (texto) {
tareas.push({
id: Date.now(),
texto,
completada: false
});
input.value = '';
renderizarApp();
}
}
function toggleTarea(id) {
const tarea = tareas.find(t => t.id === id);
if (tarea) {
tarea.completada = !tarea.completada;
renderizarApp();
}
}
function eliminarTarea(id) {
tareas = tareas.filter(t => t.id !== id);
renderizarApp();
}
// Componente principal
function appTareas() {
return html`
<div class="todo-app">
<h1>Lista de Tareas</h1>
<div class="agregar-tarea">
<input
id="nueva-tarea"
placeholder="Nueva tarea..."
@keyup=${(e) => e.key === 'Enter' && agregarTarea()}
>
<button @click=${agregarTarea}>Agregar</button>
</div>
<ul class="lista-tareas">
${tareas.map(tarea => html`
<li class="tarea ${tarea.completada ? 'completada' : ''}">
<input
type="checkbox"
.checked=${tarea.completada}
@change=${() => toggleTarea(tarea.id)}
>
<span>${tarea.texto}</span>
<button @click=${() => eliminarTarea(tarea.id)}>Eliminar</button>
</li>
`)}
</ul>
<p>Total: ${tareas.length} tareas</p>
</div>
`;
}
function renderizarApp() {
render(appTareas(), document.getElementById('app'));
}
// Inicializar la aplicación
renderizarApp();
Integración con Web Components
lit-html se integra perfectamente con Web Components:
import { html, render } from 'lit-html';
class MiComponente extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
render() {
render(html`
<style>
:host {
display: block;
padding: 1rem;
border: 1px solid #ccc;
}
</style>
<div>
<h3>Mi Componente Web</h3>
<slot></slot>
</div>
`, this.shadowRoot);
}
}
customElements.define('mi-componente', MiComponente);
Comparación con otros frameworks
Característica | lit-html | React | Vue | Svelte |
---|---|---|---|---|
Tamaño | ~5KB | ~42KB | ~34KB | ~12KB |
Curva de aprendizaje | Baja | Media | Baja | Media |
Build necesario | No | Sí | Sí | Sí |
Sintaxis | Template literals | JSX | Template | Template |
Rendimiento | Excelente | Bueno | Bueno | Excelente |
Mejores prácticas
1. Organización del código
// Separar lógica de presentación
function crearTemplate(datos) {
return html`...`;
}
function manejarEventos() {
// Lógica de eventos
}
function renderizar() {
render(crearTemplate(datos), contenedor);
}
2. Reutilización de componentes
function boton(texto, onClick, variante = 'primary') {
return html`
<button
class="btn btn-${variante}"
@click=${onClick}
>
${texto}
</button>
`;
}
// Uso
const template = html`
${boton('Guardar', guardarDatos, 'success')}
${boton('Cancelar', cancelar, 'secondary')}
`;
3. Optimización de rendimiento
// Usar repeat para listas grandes
${repeat(items, item => item.id, item => html`...`)}
// Evitar re-renderizados innecesarios
const template = html`...`;
render(template, contenedor);
// Solo llamar render cuando los datos cambien
Debugging y herramientas
1. DevTools
Instala la extensión de Chrome para lit-html:
npm install -g lit-html-devtools
2. Logging de cambios
import { html, render } from 'lit-html';
// Wrapper para debugging
function renderWithLogging(template, container) {
console.log('Renderizando template:', template);
render(template, container);
}
Recursos útiles
- Documentación oficial de lit-html
- Guía de directivas
- Ejemplos y demos
- GitHub de lit-html
- Framework Lit completo
Conclusión
lit-html es una excelente opción para crear interfaces web modernas sin el peso de un framework completo. Su simplicidad, rendimiento y flexibilidad lo hacen ideal para:
- Proyectos pequeños a medianos
- Micro-frontends
- Prototipos rápidos
- Componentes reutilizables
- Aplicaciones donde el tamaño importa
¿Listo para crear interfaces web ligeras y eficientes?
¡Con lit-html, tienes el poder de React sin la complejidad!