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 de texto sin formato y HTML con 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.

A menudo, los desarrolladores terminan implementando su propia vista de editor personalizada que implementa la funcionalidad que necesitan sus usuarios. La vista del editor se puede compilar con un DOM complejo, o incluso con un elemento <canvas>, pero como la única forma de que el desarrollador reciba entradas de texto requiere un elemento editable enfocado, deberá colocar un elemento contenteditable oculto en algún lugar de su página.

El resultado es que, mientras el usuario parece editar directamente el contenido en la vista de editor personalizada de la app, el desarrollador en realidad recibe la entrada con controladores de eventos en el elemento oculto y, luego, la refleja en la vista de editor visible. Esto puede generar problemas, ya que el desarrollador termina luchando con el comportamiento de edición predeterminado del navegador en el elemento contenteditable oculto.

Para abordar este tipo 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 directamente sin estar vinculados 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 coeditar 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, el editor no se actualizará para mostrar los cambios de otros usuarios hasta que el usuario del IME haya terminado su redacción. Esto se debe a que realizar cambios en el área del DOM que se está editando mientras hay una composición de IME activa puede hacer que la composición se cancele antes de tiempo. La aplicación debe esperar hasta que se cierre la ventana del IME para actualizar la vista, lo que puede causar demoras y dificultar la colaboración.

Problemas para colaborar en Word Online mientras redactas texto

Para proporcionar una mejor experiencia del usuario y del desarrollador, los desarrolladores necesitan una forma de desacoplar la entrada de texto de la vista del DOM HTML. 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 plataforma de la API de EditContext, en lugar de observar cambios en el DOM. Esto permite un control más estricto sobre cómo se controla la entrada y hasta permite agregar capacidad de edición al elemento <canvas>.

Si asocias una instancia de EditContext con un elemento, este se vuelve editable:

// 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 tareas que debes realizar cuando usas 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 otras IU de edición específicas de la plataforma.

Cómo aplicar formato

Escucha el evento textformatupdate y aplica el formato que especifica el evento a la vista del editor. Los IME usan estas decoraciones de texto cuando se escriben ciertos idiomas. Por ejemplo, un IME en japonés utilizará subrayado para mostrar qué parte del texto se redacta activamente.

Captura de pantalla de la ventana del Editor de método de entrada (Input Method Editor) que se usa para ingresar caracteres japoneses.

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

Escucha el evento beforeinput para controlar los comportamientos de edición de texto enriquecido que quieras admitir, como las combinaciones de teclas para aplicar texto en negrita o en cursiva, o aplicar una corrección ortográfica.

Cómo administrar los cambios en las selecciones del usuario

Cuando la selección del usuario cambie debido a la entrada del teclado o del mouse, deberás informar el cambio a la instancia de EditContext. Esto es necesario debido a la aplicabilidad de la API de EditContext a una amplia variedad 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 los comportamientos de selección y navegación con el cursor de texto, 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>.

EditContext en comparación con contenteditable

EditContext es una excelente opción si estás implementando un editor con todas las funciones y deseas tener el 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, teniendo en cuenta todos los requisitos anteriores para usar EditContext, si todo lo que necesitas es compatibilidad simple con la edición de texto, es probable que aún quieras usar <input>, elementos <textarea> o el atributo contenteditable.

Mirando hacia el futuro

El equipo de Microsoft Edge implementó EditContext en Chromium en colaboración con los ingenieros de Chrome, y se lanzará 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 a los desarrolladores web les resulte más fácil crear potentes experiencias de edición personalizadas en la Web, y creemos que la API de EditContext logra esto abordando los desafíos existentes y ofreciendo una forma más directa de manejar las entradas de texto.

Si quieres 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 con la implementación de la API, envía un informe a crbug.com.