Presentamos una nueva forma de crear experiencias de edición web personalizadas con la API de EditContext

No siempre ha sido una tarea sencilla para los desarrolladores incorporar capacidades de edición avanzadas en sus aplicaciones web. La plataforma web permite editar documentos HTML y de texto sin formato mediante elementos como <input> y <textarea>, o aplicando el atributo contenteditable a los elementos. Sin embargo, las capacidades básicas de estos tipos de elementos a menudo no son suficientes para lo que los desarrolladores quieren lograr en sus apps.

Los desarrolladores suelen terminar implementando sus propias vistas de editor personalizadas con las funciones que necesitan sus usuarios. La vista del editor puede compilarse con un DOM complejo, o incluso con un elemento <canvas>, pero como la única forma en que el desarrollador recibe una entrada de texto requiere un elemento editable y enfocado, deberá colocar un elemento contenteditable oculto en su página en alguna parte.

El resultado es que, si bien el usuario parece estar editando directamente el contenido en la vista del editor personalizado de la app, el desarrollador recibe la entrada con controladores de eventos en el elemento oculto y luego la duplica en la vista del editor visible. Esto puede provocar problemas, ya que el desarrollador termina luchando con el comportamiento de edición predeterminado del navegador en el elemento contenteditable oculto.

Para abordar esta clase de problemas, el equipo de Microsoft Edge impulsó la estandarización de EditContext, una nueva API de plataforma web que permite a los desarrolladores recibir entradas de texto de forma directa sin estar vinculado a los comportamientos de edición predeterminados del navegador.

Un ejemplo del mundo real

Por ejemplo, cuando los usuarios colaboran en Word Online. Los usuarios pueden editar en conjunto y ver los cambios y las posiciones del cursor de los demás. Sin embargo, si un colaborador usa una ventana del Editor de método de entrada (IME) para redactar texto en japonés, por ejemplo, su editor no se actualizará para mostrar los cambios de otros usuarios hasta que el usuario del IME haya terminado su composición. Esto se debe a que realizar cambios en el área del DOM que se está editando mientras haya una composición de IME activa puede provocar que esta se cancele prematuramente. La aplicación debe esperar hasta que se cierre la ventana del IME para actualizar la vista, lo que puede causar demoras y entorpecer la colaboración.

Problemas para colaborar en Word Online mientras redactas texto

Para brindar una mejor experiencia a los desarrolladores y a los usuarios, los desarrolladores necesitan una forma de separar las entradas de texto de la vista HTML DOM. La API de EditContext es la solución a este problema.

Conceptos básicos de EditContext

Con EditContext, puedes recibir entradas de texto y composición directamente a través de la superficie de la API de EditContext, en lugar de observar los cambios en el DOM. Esto permite tener un mayor control sobre cómo se maneja la entrada y también permite agregar edición al elemento <canvas>.

Asociar una instancia de EditContext con un elemento hace que se pueda editar:

// This will be our editable element.
const element = document.querySelector('#editor-element');

// Creating the EditContext object.
const editContext = new EditContext();

// Associating the EditContext object with our DOM element.
// The element is now focusable and can receive text input.
element.editContext = editContext;

// In order to render the text typed by the user onto the
// page, as well as the user's selection, you'll need to
// receive the input in a textupdate event callback.
editContext.addEventListener('textupdate', event => {
  element.textContent = editContext.text;

  // For brevity, the code to render the selection
  // isn't shown here.
    renderSelection(event.selectionStart, event.selectionEnd);
 });

Responsabilidades del autor

El uso de la API de EditContext facilita la compatibilidad con métodos de entrada avanzados, como ventanas de composición de IME, selectores de emojis y otras plataformas de entrada del sistema operativo. Para que todo esto sea posible en tu elemento editable, la API de EditContext requiere cierta información. Además de renderizar el texto y la selección, hay otras acciones que debes realizar cuando uses la API de EditContext.

Administrar el lado de una región editable o si cambia la selección del usuario

Llama a los métodos updateControlBounds() y updateSelectionBounds() para informar a la instancia de EditContext cada vez que cambie el tamaño de la región editable o la selección del usuario. Esto ayuda a la plataforma a decidir dónde mostrar las ventanas del IME y otras IU de edición específicas de la plataforma.

// It's necessary to provide bounds information because EditContext
// is generic enough to work with any type of web editor, even
// <canvas>-based editors. The API doesn't make any assumptions as
// to how the editor is implemented or how the selection is rendered.
// Bounds are given in the client coordinate space.
const controlBound = editorElement.getBoundingClientRect();
const selection = document.getSelection();
const selectionBound = selection.getRangeAt(0).getBoundingClientRect();
editContext.updateControlBounds(controlBound);
editContext.updateSelectionBounds(selectionBound);

Administra la posición de la IU del editor

Escucha el evento characterboundsupdate y llama a updateCharacterBounds() en respuesta para ayudar a la plataforma a decidir dónde mostrar las ventanas del IME y otra IU de edición específica de la plataforma.

Aplicando formato

Escucha el evento textformatupdate y aplica el formato especificado por el evento a tu vista de editor. Los IME usan estas decoraciones de texto cuando redactan ciertos idiomas. Por ejemplo, un IME japonés usará un subrayado para mostrar qué parte del texto se está componiendo de forma activa.

Captura de pantalla de una ventana del Editor de método de entrada que se usa para ingresar caracteres japoneses.

Cómo manejar los comportamientos de edición de texto enriquecido

Escucha el evento beforeinput para controlar cualquier comportamiento de edición de texto enriquecido que desees admitir, como las teclas de acceso rápido para colocar texto en negrita o cursiva, o aplicar una corrección ortográfica.

Administración de cambios en las selecciones de usuarios

Cuando la selección del usuario cambie debido a una entrada del teclado o del mouse, deberás informar a la instancia de EditContext el cambio. Esto es necesario debido a la aplicabilidad de la API de EditContext a una gran cantidad de casos de uso, incluidos los editores renderizados con el elemento <canvas> en los que el navegador no puede detectar los cambios de selección automáticamente.

document.addEventListener('selectionchange', () => {
  const selection = document.getSelection();

  // EditContext doesn't handle caret navigation, so all the caret navigation/selection that happens
  // in DOM space needs to be mapped to plain text space by the author and passed to EditContext.
  // This example code assumes the editable area only contains text under a single node.
  editContext.updateSelection(selection.anchorOffset, selection.focusOffset);
});

Si el elemento que usas con EditContext es un elemento <canvas>, también deberás implementar comportamientos de selección y navegación con signo de intercalación, como navegar por el texto con las teclas de flecha. Además, el corrector ortográfico integrado del navegador solo funciona en elementos que no sean <canvas>.

Comparación entre EditContext y contenteditable

EditContext es una excelente opción si implementas un editor con todas las funciones y deseas tener control total sobre cómo se maneja la entrada de texto o si agregas funciones avanzadas, como la edición colaborativa con varios usuarios. Sin embargo, dados todos los requisitos anteriores para usar EditContext, si todo lo que necesitas es una simple compatibilidad con la edición de texto, es probable que te convenga usar elementos <input>, <textarea> o el atributo contenteditable.

Proyecciones para el futuro

El equipo de Microsoft Edge implementó EditContext en Chromium a través de la colaboración con ingenieros de Chrome. El lanzamiento se realizará con la versión 121 (enero de 2024) de Chrome y Edge. Por ahora, solo está disponible en navegadores basados en Chromium, pero puedes leer las posiciones de Mozilla y WebKit en la API de EditContext.

Queremos que sea más fácil para los desarrolladores web crear experiencias potentes de edición personalizadas en la Web, y creemos que la API de EditContext logra esto abordando desafíos existentes y ofreciendo una forma más directa de manejar las entradas de texto.

Si deseas obtener más información sobre la API, consulta la documentación de MDN. Para enviar comentarios sobre el diseño de la API, abre un problema en el repositorio de GitHub de la API de EditContext. Para informar errores relacionados con la implementación de la API, envía un informe de errores en crbug.com.