document.querySelector stops at two walls: a shadow root and an iframe. Plenty
of support forms put the description field behind one of them — a WYSIWYG editor
is usually an iframe, and a design-system form control is usually a custom
element with a shadow root.
Every selector the deflector accepts understands two operators for this, and
they compose with ordinary CSS on both sides.
The operators
The part before the operator selects the host — the
<iframe> element, or the
element with the shadow root. The part after it is a selector inside.
Operators nest one level of each, which covers every real form we have seen: one
iframe inside one shadow root. If yours is deeper, tell us what it is — the
limit is arbitrary, not fundamental.
Same-origin only
An iframe from another origin cannot be read by any script on your page, ours included. There is no operator for it and no workaround. If your form is a cross-origin embed from your helpdesk vendor, install the deflector inside that form’s own template instead — most hosted helpdesks allow custom JavaScript on the form itself, which is the same page as the field. The deflector logs and steps over a frame it cannot reach rather than throwing. The page is not ours to break.Rich-text fields
A WYSIWYG field’s value is HTML. Sent as-is it reaches the model as tag soup and retrieves on the tag names. Set:Plain fields the deflector already handles
You do not need an operator for these:- A bare word is tried as a selector, then as
[name="…"], then as an id.descriptionfinds<textarea name="description">. - A
<select>sends its visible label, not its value —3tells a model nothing,Billingdoes. - A
contenteditablediv is read as text. - A submit button outside its form still resolves to the form it belongs to.
Debugging a selector
Turn ondata-debug-mode="true". Every selector that fails to match is named in
the console, including the anchor and the hand-off target — the two that
otherwise fail completely silently.
To check a selector by hand from the console, remember the operators are ours,
not the browser’s. Test each half separately: