-
Notifications
You must be signed in to change notification settings - Fork 247
Add getRangeFromValue() explainer #1075
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@microsoft-github-policy-service agree |
GetRangeFromValue/explainer.md
Outdated
|
||
## Proposed Approach | ||
|
||
The `getRangeFromValue()` API will create a Range representing the `value` of a `<textarea>` or `<input>` element. It accepts two parameters: start_offset and end_offset. These parameters determine the start and end nodes, and their offsets, within the Range object, considering the specific DOM structure of these elements. In an `<input>`, the range is always within a single text node holding the value. In contrast, a `<textarea>` may have multiple text nodes if line breaks are present, potentially resulting in different start and end nodes. Importantly, the element itself will never be the start or end node. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that it's already possible to get a Range
pointing to text inside a <textarea>
. For example:
https://codepen.io/daniec/pen/xbwKPzz?editors=1000
When calling getBoundingClientRect()
on such a range, the DOMRect that's returned is empty at 0, 0.
So it seems there are two possibilities here to to make Use Case 1 work.
- We change the behavior of Range such that any range placed on text inside a text area returns the actual coordinates when
getBoundingClientRect()
is called. But thengetRangeFromValue()
is not really needed for<textarea>
, only for<input>
. - Make the Ranges returned from
getRangeFromValue()
"special" in that they can return actual coordinates forgetBoundingClientRect()
in a textarea. But this seems potentially confusing. Would this specialness be exposed to JavaScript in any kind of explicit way?
And do we have the same issue for using Ranges in a <textarea>
to draw custom highlights?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating a Range that targets text inside a <textarea>
is only possible by referencing its DOM text node. This node exists only if the <textarea>
has a default value set in the HTML—like in your CodePen example:
<textarea>We are trying something out here</textarea>
However, there's an important caveat:
- If the user hasn’t typed anything into the field (in other words, there has been no user interaction), the
textarea.value
and its text node (textarea.firstChild.nodeValue
) will be synchronized. Meaning, updating the text node like this:textarea.firstChild.nodeValue = "Arbitrary Value";
will also update the value of the<textarea>
, as well as what is displayed in the field itself.
Demo Sequence for this CodePen:
Display Text → Display Value → Change Text Node Through JS → Display Text → Display Value
- However, once the user types into the field, the synchronization between the text node and the field
value
will break. Thevalue
attribute will reflect the user’s input, but the text node will remain unchanged. This means that if you checktextarea.firstChild.nodeValue
, after manually editing the field, it will still show the original HTML value. In addition, the text rendered on the field will no longer match the text node in the DOM.
Demo sequence in the CodePen:
Display Text → Display Value → Manually Change Textarea Input → Display Text → Display Value
Once it gets to this point, modifying the text node via JavaScript won’t affect what’s rendered or the value
property. Even clearing the field manually (through backspace) won’t restore the sync.
And so, while it’s technically possible to create a Range
inside a <textarea>
, its usefulness is very limited due to this behavior. The <textarea>
would need to be static and not accept user input, which in most use cases would defeat the purpose of using an input field altogether.
This behavior also applies to <input>
elements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for that explanation! That's interesting, I didn't know that the synchronization breaks once the user has edited the field.
Isn't this also a problem for getRangeFromValue()
though? Once synchronization has broken, what is the startContainer/endContainer of the Range that getRangeFromValue()
returns?
GetRangeFromValue/explainer.md
Outdated
|
||
## Proposed Approach | ||
|
||
The `getRangeFromValue()` API will create a Range representing the `value` of a `<textarea>` or `<input>` element. It accepts two parameters: start_offset and end_offset. These parameters determine the start and end nodes, and their offsets, within the Range object, considering the specific DOM structure of these elements. In an `<input>`, the range is always within a single text node holding the value. In contrast, a `<textarea>` may have multiple text nodes if line breaks are present, potentially resulting in different start and end nodes. Importantly, the element itself will never be the start or end node. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the <input>
case I'd like to understand more about the Text node that will be the Range's startContainer/endContainer. Currently no Text node is exposed to script for an <input>
element, so this would be something new. Several questions come to mind:
- Is this Text Node connected to the DOM in any way? Or does it have no parent?
- What happens when this Text Node is moved or modified? Are those changes reflected in the
<input>
? - Are changes to the
<input>
reflected in the Text node? Or is a new Text node created? - Should we provide a more direct way to get this special Text node from an
<input>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right: currently, no text node is exposed to scripts for <input>
elements. However, that only applies to the Light DOM, because both <input>
and <textarea>
elements rely on internal text nodes for rendering, hidden within the Shadow DOM. These are the text nodes that are used to create the Range
object through getRangeFromValue()
. Since they are used for rendering, every input change made to an <input>
or <textarea>
element updates the nodes accordingly. The same holds true for the other way around, albeit not something that can be currently done on web developers' end, as far as I am aware. One of our proposals before getRangeFromValue() was to expose these text nodes, and have them be used to manually create a Range
on the web developers' end, something like this:
const range = new Range();
range.setStart(inputInternalTextNode, 0);
range.setStart(inputInternalTextNode, 6);
However, these text nodes are hidden in the Shadow DOM for optimization purposes, and exposing them as they are in the Light DOM would entail modifying that logic and handling performance implications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summarizing discussion from our call earlier today:
- We can't do anything that would expose nodes from inside a
<textarea>
or<input>
shadow DOM to script on a webpage. - So @t-andresre will spend some time exploring whether a special Range type could be invented that would satisfy these use cases without actually exposing the Text node.
- Based on the result of that investigation, we'll decide whether to move forward with that approach or go back to the more scoped
getSelectionBoundingClientRect
proposal.
Co-authored-by: Dan Clark <daniec@microsoft.com>
Co-authored-by: Dan Clark <daniec@microsoft.com>
Co-authored-by: Dan Clark <daniec@microsoft.com>
This PR adds the getRangeFromValue() explainer & issue template, updates the README.md file.