Ignore dynamic attributes in the HTML (e.g. ARIA attributes added by Tippy.js)

We are trying to show a Tippy.js tooltip from certain HTML nodes that are rendered by ProseMirror, but Tippy.js by default adds ARIA attributes to the node it bases it position from, which ProseMirror will immediately from its MutationObserver, is there any way to make ProseMirror ignore such attributes as they don’t need to effect the actual document, nor should they be removed by ProseMirror. (In actually, it looks like ProseMirror recreates the HTML element itself rather than only remove the attribute, which causes Tippy.js to trigger again, in a loop).

I can disable aria attributes in Tippy.js, but that’s less ideal for accessibility.

1 Like

@segevfiner

This is my way. Hopefully @marjin will consider adding it to the codebase


    // @ts-ignore
    const original = view.domObserver.registerMutation;
    // @ts-ignore
    view.domObserver.registerMutation = function (this: any, mut: MutationRecord, added: ProsemirrorNode[]) {
      // console.log('wealthy registerMutation', mut, added);
      if (added.length === 0 && (mut.type === 'attributes') && (mut.attributeName === 'data-aria-hidden' || mut.attributeName === 'aria-hidden')) {
        return;
      }

      return original.call(this, mut, added);
    }

Ran into a similar issue with integrating a Radix dropdown menu with ProseMirror. When modal=true, the menu component uses GitHub - theKashey/aria-hidden: 🗣Cast aria-hidden to everything, except... to add aria-hidden and data-aria-hidden to all other elements.

For some reason, only with a CodeMirror Nodeview, it causes the node selection to be lost because there are mutations pending when domObsever.stop() is called when view dom is blurred.

There are no mutations if I don’t use a CodeMirror node view.

	ignoreMutation() {
		return true;
	}

	stopEvent(event: Event) {
		return this.cmView && this.cmView.dom.contains((event as any).target);
	}

Unsure about the consequences for accessibility but adding the following helps, because it excludes ProseMirror descendants from receiving aria-hidden. This only works if you’re directly or indirectly using GitHub - theKashey/aria-hidden: 🗣Cast aria-hidden to everything, except....

	new Plugin({
		props: {
			attributes: {
				'aria-live': 'polite',
			},
		},
	}),

I was debugging why I only noticed a domObserver issue with aria-hidden when I had a CodeMirror node view. It’s because it has a cm-announced which has aria-live set, so the library aria-hidden marks all of its surrounding siblings as hidden instead of its parent or an ancestor – and that in turn, causes a bunch of mutation records.

Similar issue:

Ideally, we could define an ignoreMutation at the root node view or passed to EditorView, that’s used in the domObserver and can filter out these third-party libraries.