Tienes un botón en tu página. Le pones un onclick="mifunción()" en el HTML, lo pruebas... y no pasa nada. O peor: funciona a veces y otras no, dependiendo de en qué orden carga el script. Aquí es donde la mayoría se atasca y no entiende por qué.
El problema casi siempre es el mismo: el código intenta acceder al botón antes de que exista en la página, o se usa la forma antigua de manejar eventos en vez de addEventListener. Este tutorial explica cómo funciona de verdad.
🤔 ¿Qué vamos a ver?
- Qué es un evento y cómo funciona
addEventListener - Los tipos de eventos más usados: click, keydown, submit, mouseover
- El event object: la información que JavaScript te da en cada evento
- Un dashboard interactivo completo como proyecto final
- Los errores concretos que todo el mundo comete al empezar
Qué es un evento en JavaScript
Cuando alguien hace clic en un botón, pulsa una tecla o envía un formulario, el navegador genera un evento. JavaScript puede "escuchar" esos eventos y ejecutar código cuando ocurren.
Es como tener un portero en la puerta: no hace nada hasta que llaman, y cuando llaman ejecuta exactamente lo que le dijiste. No antes, no después.
La forma moderna de registrar esa escucha es addEventListener. Antes se usaba onclick directamente en el HTML, pero eso mezcla estructura con comportamiento y da problemas cuando tienes varios scripts. Esto me costó pillarlo al principio porque los tutoriales viejos siguen usando el método antiguo.
❌ Error común:
"¡Mi código no hace nada cuando hago clic!"
El problema más habitual: el script se ejecuta antes de que el HTML esté cargado. JavaScript intenta encontrar el botón, no existe todavía, y falla en silencio. Solución: pon el script al final del <body> o usa DOMContentLoaded.
Tu primer addEventListener
Vamos con el ejemplo más básico posible: un botón que cambia de color al hacer clic.
Paso 1: el HTML
Necesitas un botón con un id para que JavaScript pueda encontrarlo:
<button id="miBoton">¡Haz clic aquí!</button>
🔍 ¿Por qué usamos id="miBoton"?
El id es como el "nombre" del botón. JavaScript lo va a usar para encontrarlo entre todos los elementos de la página. Es como buscar a una persona por su nombre en una multitud.
Paso 2: el JavaScript
Ahora le dices a JavaScript: cuando alguien haga clic en ese botón, ejecuta esta función.
// Paso 1: Encontrar el botón en la página
const boton = document.getElementById("miBoton");
// Paso 2: Crear la función que va a ejecutarse
function cambiarColor() {
boton.style.backgroundColor = "red";
boton.textContent = "¡Funcionó!";
}
// Paso 3: Decirle al botón que escuche clics
boton.addEventListener("click", cambiarColor);
Qué hace cada línea
💡 Línea 1: const boton = document.getElementById("miBoton");
document= Toda tu página webgetElementById= "Busca el elemento que tiene este id""miBoton"= El id que pusimos en el HTMLconst boton == Guarda ese elemento en una variable llamada "boton"
💡 Líneas 3-6: La función cambiarColor
- Esta función contiene las instrucciones de qué hacer cuando alguien haga clic
boton.style.backgroundColor = "red"→ Cambiar el fondo a rojoboton.textContent = "¡Funcionó!"→ Cambiar el texto del botón
💡 Línea 8: addEventListener("click", cambiarColor)
addEventListener= "Escucha un tipo de evento""click"= El tipo de evento (en este caso, clics)cambiarColor= La función que se ejecutará cuando pase el evento
❌ El error que comete todo el mundo al principio:
Escribir cambiarColor() con paréntesis en lugar de cambiarColor
Con paréntesis → la función se ejecuta al cargar la página, no al hacer clic
Sin paréntesis → la función se ejecuta cuando ocurre el evento
// ❌ MAL: Se ejecuta al cargar la página
boton.addEventListener("click", cambiarColor());
// ✅ BIEN: Se ejecuta cuando hagan clic
boton.addEventListener("click", cambiarColor);
Pruébalo antes de seguir
✅ Verifica que tu código funcione:
El event object: la información del evento
Cuando ocurre un evento, JavaScript no solo ejecuta tu función, también le pasa un objeto con información sobre lo que pasó: qué elemento se pulsó, en qué posición, qué tecla fue... La mayoría ignora esto al principio y luego se pregunta cómo detectar qué botón se pulsó cuando hay varios.
Para acceder a esa información, declara un parámetro en tu función (normalmente se llama event o simplemente e):
function manejarClick(event) {
// "event" contiene información sobre el clic
console.log("Tipo de evento:", event.type);
console.log("Elemento clickeado:", event.target);
console.log("Posición X del clic:", event.clientX);
console.log("Posición Y del clic:", event.clientY);
// Cambiamos el color basado en la posición X
if (event.clientX > 200) {
event.target.style.backgroundColor = "blue";
} else {
event.target.style.backgroundColor = "green";
}
}
boton.addEventListener("click", manejarClick);
🔍 ¿Qué información me da el event object?
event.type→ Tipo de evento ("click", "keydown", etc.)event.target→ El elemento que fue clickeadoevent.clientX→ Posición horizontal del clicevent.clientY→ Posición vertical del clicevent.key→ Qué tecla fue presionada (en eventos de teclado)
🚨 Para ver el console.log:
- Abre tu página en el navegador
- Presiona F12 (o clic derecho → "Inspeccionar")
- Ve a la pestaña "Console"
- Haz clic en tu botón
- ¡Verás toda la información del evento!
Los eventos más usados
Hay decenas de tipos de eventos, pero en el día a día vas a usar siempre los mismos cuatro o cinco. Estos son los que necesitas conocer:
Evento "click"
// Se ejecuta cuando haces clic
miElemento.addEventListener("click", function() {
alert("¡Me clickearon!");
});
Eventos "mouseover" y "mouseout"
// Cuando el mouse entra al elemento
miElemento.addEventListener("mouseover", function() {
this.style.backgroundColor = "yellow";
});
// Cuando el mouse sale del elemento
miElemento.addEventListener("mouseout", function() {
this.style.backgroundColor = "white";
});
💡 ¿Qué es "this"?
this se refiere al elemento que disparó el evento. Es como decir "yo mismo".
Si el botón dice this.style.color = "red", está diciendo "cambia MI color a rojo".
Eventos de teclado: "keydown" y "keyup"
// Necesitas un input para capturar teclas
const input = document.getElementById("miInput");
// Cuando presionas una tecla
input.addEventListener("keydown", function(event) {
console.log("Presionaste:", event.key);
// Ejemplo: Si presionas Enter
if (event.key === "Enter") {
alert("¡Presionaste Enter!");
}
});
Evento "submit" en formularios
// Para formularios completos
const formulario = document.getElementById("miFormulario");
formulario.addEventListener("submit", function(event) {
event.preventDefault(); // ¡Importante!
alert("Formulario enviado sin recargar página");
});
⚠️ No te olvides de event.preventDefault()
Sin esa línea, al enviar el formulario la página se recarga y pierdes todo. preventDefault() cancela el comportamiento por defecto del navegador para que puedas controlarlo tú con JavaScript.
Proyecto: Dashboard Interactivo
Juntamos todo lo anterior en un proyecto real: un dashboard que responde a clics, teclas, formularios y eventos de teclado global. Es el tipo de cosa que construyes en cualquier aplicación web.
El HTML del Dashboard
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mi Dashboard Interactivo</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f0f0f0;
}
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.card {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
button {
padding: 10px 20px;
margin: 5px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
input, select {
width: 100%;
padding: 8px;
margin: 5px 0;
border: 1px solid #ddd;
border-radius: 4px;
}
.contador {
font-size: 48px;
text-align: center;
margin: 20px 0;
color: #333;
}
.notificacion {
display: none;
background: #4CAF50;
color: white;
padding: 10px;
position: fixed;
top: 20px;
right: 20px;
border-radius: 4px;
z-index: 1000;
}
</style>
</head>
<body>
<h1>🚀 Mi Dashboard Interactivo</h1>
<!-- Notificación -->
<div id="notificacion" class="notificacion">¡Acción completada!</div>
<div class="dashboard">
<!-- Card 1: Botones de tema -->
<div class="card">
<h3>🎨 Cambiar tema</h3>
<button id="temaClaro" style="background: #e3f2fd;">Tema Claro</button>
<button id="temaOscuro" style="background: #424242; color: white;">Tema Oscuro</button>
<button id="temaColorido" style="background: linear-gradient(45deg, #ff6b6b, #4ecdc4);">Tema Colorido</button>
</div>
<!-- Card 2: Contador -->
<div class="card">
<h3>🔢 Contador Interactivo</h3>
<div id="contador" class="contador">0</div>
<button id="sumar" style="background: #4CAF50; color: white;">+ Sumar</button>
<button id="restar" style="background: #f44336; color: white;">- Restar</button>
<button id="resetear" style="background: #ff9800; color: white;">Reset</button>
</div>
<!-- Card 3: Formulario interactivo -->
<div class="card">
<h3>📝 Formulario con Validación</h3>
<form id="miFormulario">
<label>Tu nombre:</label>
<input type="text" id="nombre" placeholder="Escribe aquí...">
<p id="feedback" style="color: #666; font-size: 14px;">Escribe algo...</p>
<button type="submit" style="background: #2196F3; color: white;">Enviar</button>
</form>
</div>
<!-- Card 4: Selector de opciones -->
<div class="card">
<h3>⚙️ Configuraciones</h3>
<label>Modo de visualización:</label>
<select id="modoVista">
<option value="normal">Normal</option>
<option value="compacto">Compacto</option>
<option value="amplio">Amplio</option>
</select>
<p id="estadoVista">Modo actual: Normal</p>
</div>
</div>
<script src="dashboard.js"></script>
</body>
</html>
El JavaScript del Dashboard
Ahora creamos el archivo dashboard.js con TODOS los event listeners. Te explico cada sección:
// 🚀 DASHBOARD INTERACTIVO - JavaScript completo
// Cada sección maneja un tipo de evento diferente
// ===== VARIABLES GLOBALES =====
let contadorActual = 0; // Para el contador
// ===== FUNCIÓN PARA MOSTRAR NOTIFICACIONES =====
function mostrarNotificacion(mensaje) {
const notif = document.getElementById('notificacion');
notif.textContent = mensaje;
notif.style.display = 'block';
// Ocultar después de 3 segundos
setTimeout(function() {
notif.style.display = 'none';
}, 3000);
}
// ===== 1. EVENTOS CLICK - Botones de tema =====
document.getElementById('temaClaro').addEventListener('click', function() {
document.body.style.backgroundColor = '#f0f8ff';
document.body.style.color = '#333';
mostrarNotificacion('✅ Tema claro activado');
});
document.getElementById('temaOscuro').addEventListener('click', function() {
document.body.style.backgroundColor = '#2c2c2c';
document.body.style.color = '#ffffff';
mostrarNotificacion('🌙 Tema oscuro activado');
});
document.getElementById('temaColorido').addEventListener('click', function() {
document.body.style.background = 'linear-gradient(45deg, #ff9a9e, #fecfef, #fecfef, #fecfef)';
document.body.style.color = '#333';
mostrarNotificacion('🌈 Tema colorido activado');
});
// ===== 2. EVENTOS CLICK - Contador =====
document.getElementById('sumar').addEventListener('click', function() {
contadorActual++; // Incrementar en 1
document.getElementById('contador').textContent = contadorActual;
// Cambiar color basado en el número
const elemento = document.getElementById('contador');
if (contadorActual > 10) {
elemento.style.color = 'red';
} else if (contadorActual > 5) {
elemento.style.color = 'orange';
} else {
elemento.style.color = 'green';
}
mostrarNotificacion(`➕ Contador: ${contadorActual}`);
});
document.getElementById('restar').addEventListener('click', function() {
contadorActual--;
document.getElementById('contador').textContent = contadorActual;
mostrarNotificacion(`➖ Contador: ${contadorActual}`);
});
document.getElementById('resetear').addEventListener('click', function() {
contadorActual = 0;
document.getElementById('contador').textContent = contadorActual;
document.getElementById('contador').style.color = '#333';
mostrarNotificacion('🔄 Contador reseteado');
});
// ===== 3. EVENTO INPUT - Validación en tiempo real =====
document.getElementById('nombre').addEventListener('input', function(event) {
const valor = event.target.value;
const feedback = document.getElementById('feedback');
if (valor.length === 0) {
feedback.textContent = 'Escribe algo...';
feedback.style.color = '#666';
} else if (valor.length < 3) {
feedback.textContent = '⚠️ Mínimo 3 caracteres';
feedback.style.color = 'orange';
} else {
feedback.textContent = `✅ Perfecto! ${valor.length} caracteres`;
feedback.style.color = 'green';
}
});
// ===== 4. EVENTO SUBMIT - Formulario =====
document.getElementById('miFormulario').addEventListener('submit', function(event) {
event.preventDefault(); // Evita que la página recargue
const nombre = document.getElementById('nombre').value;
if (nombre.length >= 3) {
mostrarNotificacion(`🎉 ¡Hola ${nombre}! Formulario enviado correctamente`);
document.getElementById('nombre').value = ''; // Limpiar
} else {
mostrarNotificacion('❌ El nombre debe tener al menos 3 caracteres');
}
});
// ===== 5. EVENTO CHANGE - Select dropdown =====
document.getElementById('modoVista').addEventListener('change', function(event) {
const modo = event.target.value;
const dashboard = document.querySelector('.dashboard');
const estado = document.getElementById('estadoVista');
switch (modo) {
case 'compacto':
dashboard.style.gap = '10px';
estado.textContent = '📦 Modo actual: Compacto';
mostrarNotificacion('📦 Vista compacta activada');
break;
case 'amplio':
dashboard.style.gap = '40px';
estado.textContent = '📏 Modo actual: Amplio';
mostrarNotificacion('📏 Vista amplia activada');
break;
default:
dashboard.style.gap = '20px';
estado.textContent = '⚖️ Modo actual: Normal';
mostrarNotificacion('⚖️ Vista normal activada');
}
});
// ===== 6. EVENTO KEYDOWN - Atajos de teclado =====
document.addEventListener('keydown', function(event) {
// Atajos con teclas especiales
if (event.key === 'Escape') {
mostrarNotificacion('⚡ Presionaste Escape');
}
// Atajo: Ctrl + R para resetear contador
if (event.ctrlKey && event.key === 'r') {
event.preventDefault();
contadorActual = 0;
document.getElementById('contador').textContent = contadorActual;
mostrarNotificacion('⚡ Contador reseteado con Ctrl+R');
}
});
// ===== MENSAJE DE BIENVENIDA =====
document.addEventListener('DOMContentLoaded', function() {
mostrarNotificacion('🚀 ¡Dashboard cargado! Prueba todos los elementos');
});
🧪 Prueba tu Dashboard
✅ Lista de verificación completa:
🚨 Si algo no funciona:
- Abre las herramientas de desarrollador (F12)
- Ve a la pestaña "Console"
- Busca mensajes de error en rojo
- Revisa que los nombres de IDs coincidan entre HTML y JavaScript
- Verifica que ambos archivos estén en la misma carpeta
Por dónde seguir
Con addEventListener tienes la base de cualquier interactividad en JavaScript. El siguiente escollo natural es gestionar varios elementos a la vez sin repetir listeners — para eso existe la delegación de eventos, que se explica en detalle en el post de manipulación del DOM.
Si el dashboard te ha resultado corto, prueba a añadirle persistencia: guarda el contador en localStorage para que no se reinicie al recargar. Eso solo son dos líneas más, y te obliga a entender cómo funciona realmente el ciclo de vida de la página.
🎯 Siguiente lectura recomendada
Si quieres entender bien cómo JavaScript encuentra y modifica elementos de la página antes de añadirles eventos:
👉 JavaScript DOM: cómo cambiar el contenido de una página webLa base que necesitas para trabajar con listeners en proyectos reales