Sebastian Gomez
Cómo Utilizar los Menús Contextuales en Extensiones de Chrome
En este post, exploraremos cómo podemos agregar funcionalidades a los menús contextuales (los menús que aparecen al hacer clic derecho) en Chrome usando las APIs disponibles. Esta guía es útil para quienes desarrollan extensiones y buscan mejorar la interacción con sus usuarios.
Recuerda que esta es una serie de posts sobre extensiones de Chrome. Si vienes desde el principio, en el capítulo 2 configuramos el manifest.json con Manifest V3 y el service worker de fondo, conceptos que usaremos aquí.
¿Qué son los Menús Contextuales?
Los menús contextuales en Chrome son aquellos que aparecen al hacer clic derecho sobre una página web. Chrome permite a quienes desarrollan extensiones agregar opciones personalizadas a estos menús, ofreciendo una mejor experiencia de usuario.
Configuración Inicial
Para empezar a trabajar con los menús contextuales, primero necesitamos otorgar los permisos necesarios en el archivo manifest.json de nuestra extensión:
{
"permissions": ["contextMenus", "scripting"],
"host_permissions": ["<all_urls>"]
}Añadimos también el permiso scripting y host_permissions porque más adelante mostraremos el resultado directamente en la página con chrome.scripting.executeScript.
Nota sobre el ciclo de vida. En Manifest V3 el script de fondo (background.js) es un service worker no persistente: Chrome lo detiene y lo vuelve a crear cuando lo necesita. Por eso la creación de menús no debe hacerse en el nivel superior del archivo, porque podría perderse al reiniciarse el worker. La forma correcta es crear los menús dentro del evento chrome.runtime.onInstalled, que se ejecuta una sola vez cuando se instala o actualiza la extensión.
Creación de un Menú Contextual
Vamos a crear un menú contextual básico que aparecerá en cualquier parte de la página web. Como explicamos arriba, registramos toda la creación de menús dentro de chrome.runtime.onInstalled en nuestro background.js:
// background.js
chrome.runtime.onInstalled.addListener(() => {
// Menú principal
chrome.contextMenus.create({
id: "myContextMenu",
title: "Mi Menú Contextual",
contexts: ["all"],
});
// Submenús: se anidan en el menú principal usando parentId
chrome.contextMenus.create({
id: "subMenu1",
parentId: "myContextMenu",
title: "Submenú 1",
contexts: ["all"],
});
chrome.contextMenus.create({
id: "subMenu2",
parentId: "myContextMenu",
title: "Submenú 2",
contexts: ["all"],
});
// Opción que solo aparece cuando hay texto seleccionado
chrome.contextMenus.create({
id: "wordCount",
title: "Contar Palabras",
contexts: ["selection"],
});
});Como ves, cada menú se define con un id único, un title y la lista de contexts en los que debe mostrarse. Los submenús usan parentId para colgar del menú principal, y la opción wordCount usa el contexto selection para aparecer únicamente cuando el usuario ha seleccionado texto.
Gestión de Eventos de Clic
Para manejar las acciones cuando el usuario selecciona una opción del menú, registramos un único listener de chrome.contextMenus.onClicked y decidimos qué hacer con un switch sobre info.menuItemId. Tener un solo listener es importante en un service worker: evita registrar varios manejadores que se ejecutarían en cada clic y mantiene la lógica en un solo lugar.
// background.js (continuación)
chrome.contextMenus.onClicked.addListener((info, tab) => {
switch (info.menuItemId) {
case "subMenu1":
console.log("Submenú 1 seleccionado");
break;
case "subMenu2":
console.log("Submenú 2 seleccionado");
break;
case "wordCount":
if (info.selectionText) {
const wordCount = info.selectionText.trim().split(/\s+/).length;
showWordCount(tab.id, wordCount);
}
break;
}
});Ejemplo de Uso: Contar Palabras Seleccionadas
Supongamos que queremos contar las palabras que el usuario ha seleccionado. Ya creamos la opción wordCount y la conectamos en el switch de arriba; ahora falta mostrar el resultado.
Aquí hay un detalle importante. En Manifest V3 el código de fondo corre en un service worker, que no tiene acceso al DOM, así que `alert()` no está disponible y lanzaría un error. En lugar de eso, inyectamos un pequeño script en la pestaña activa con chrome.scripting.executeScript para mostrar el conteo en la propia página:
// background.js (continuación)
function showWordCount(tabId, count) {
chrome.scripting.executeScript({
target: { tabId },
// El argumento se pasa al script inyectado a través de "args"
args: [count],
func: (wordCount) => {
// Este código sí corre en la página, donde el DOM existe
window.alert(`Número de palabras: ${wordCount}`);
},
});
}Tip. Si prefieres no interrumpir al usuario con una ventana, otras alternativas correctas para un service worker son enviar un mensaje a un content script con chrome.tabs.sendMessage o mostrar una notificación del sistema con chrome.notifications. Lo importante es no usar APIs del DOM directamente desde el service worker.
Eliminación y Actualización de Menús Contextuales
Además de crear menús contextuales, también podemos eliminarlos o actualizarlos según sea necesario.
Para eliminar un menú contextual, usamos chrome.contextMenus.remove:
chrome.contextMenus.remove("subMenu2", () => {
console.log("Submenú 2 eliminado");
});Para actualizar un menú contextual, usamos chrome.contextMenus.update:
chrome.contextMenus.update("myContextMenu", {
title: "Mi Menú Contextual Actualizado",
});Estas operaciones puedes ejecutarlas dentro de tus propios listeners (por ejemplo, en respuesta a otro clic o a un mensaje), no es necesario que vivan dentro de onInstalled.
Conclusión
Los menús contextuales son una herramienta poderosa para mejorar la interactividad de tus extensiones de Chrome. Con la API chrome.contextMenus puedes personalizar estos menús para ofrecer funcionalidades específicas que mejoren la experiencia del usuario. La clave bajo Manifest V3 es respetar el ciclo de vida del service worker: crea los menús en onInstalled, usa un solo listener de onClicked y muestra resultados en la página con chrome.scripting, no con APIs del DOM.
Ejercicios propuestos
- Crea una extensión con un menú contextual que solo aparezca sobre imágenes (contexto
image) y que registre en consola la URL de la imagen al hacer clic. - Amplía el ejemplo de "Contar Palabras" para que, además del total, muestre cuántos caracteres tiene la selección. Pásalos como argumentos al script inyectado.
- Sustituye el
window.alertinyectado por una notificación del sistema conchrome.notifications. Compara las dos experiencias de usuario.
Resumen en 3 puntos
- En Manifest V3 los menús se crean dentro de
chrome.runtime.onInstalledporque el service worker de fondo no es persistente. - Maneja todos los clics con un único listener de
chrome.contextMenus.onClickedy unswitch (info.menuItemId)para mantener la lógica ordenada. - El service worker no tiene DOM, así que en vez de
alert()muestra resultados en la página conchrome.scripting.executeScript, un mensaje a un content script ochrome.notifications.
Eso es todo, espero que este post te haya sido útil para entender cómo trabajar con menús contextuales en Chrome y que lo puedas aplicar a alguna extensión que tengas en mente.
Déjame un comentario si te sirvió, si quieres añadir alguna opinión o si tienes alguna duda. Y recuerda que si te gustó, también puedes compartirlo usando los links a las redes sociales aquí abajo. ¡Hasta la próxima!
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.