Skip to content

selectionStart/selectionEnd behavior needs to be specified #2424

Closed

Description

@bzbarsky

Right now the spec is pretty much silent on how this stuff works, and as a result browsers have all sorts of behavior differences, both internally and across browsers. Some examples:

  1. In Chrome, var x = document.createElement(tag); x.defaultValue = "abc"; alert(x.selectionStart); will alert 0 if tag is "input" but 3 if tag is "textarea".

  2. In Safari, var x = document.createElement("textarea"); x.defaultValue = "abc"; alert(x.selectionStart); alerts 0. So do var x = document.createElement("textarea"); document.body.appendChild(x); x.defaultValue = "abc"; alert(x.selectionStart); and var x = document.createElement("textarea"); x.selectionStart = x.selectionStart; x.defaultValue = "abc"; alert(x.selectionStart);. But var x = document.createElement("textarea"); document.body.appendChild(x); x.selectionStart = x.selectionStart; x.defaultValue = "abc"; alert(x.selectionStart); alerts 3.

  3. In Gecko... there are various inconsistencies, esp between textarea vs input, display:none vs non-display-none, etc. I'm fixing some of this stuff right now, so not sure it's worth going into the details, which are changing.

OK, what does the spec actually say? It says that setting the "value" IDL attribute of an input that is in "value" mode will move the text entry cursor (if there is one!) to the end of the text.

It also says that setting the "value" IDL attribute of textarea should do the same thing.

It says that UAs must "follow platform conventions to determine their initial state" for the text entry cursor and selection.

That's it. There's no indication of how this initial state should get modified when the value or default value changes...

Activity

  1. bzbarsky commented on Mar 8, 2017

    @bzbarsky
    ContributorAuthor

    So here is a proposal for specific behavior:

    1. The initial state of the text entry cursor is at the beginning of the text control. The web depends on this behavior, looks like; see https://bugzilla.mozilla.org/show_bug.cgi?id=1337392

    2. Setting .value moves the text entry cursor to the end.

    3. Anything else that modifies a value just ensures that the text entry cursor is at some position in the range [0, newlength], clamping it to end as needed.

    This is what I tentatively plan to implement in Gecko.

  2. bzbarsky commented on Mar 8, 2017

    @bzbarsky
    ContributorAuthor

    @cdumez @domenic @travisleithead

    Note that I haven't had a chance to test Edge, so maybe it's got sane behavior....

  3. domenic commented on Mar 8, 2017

    @domenic
    Member

    /cc @tkent-google

    Anything else that modifies a value just ensures that the text entry cursor is at some position in the range [0, newlength], clamping it to end as needed.

    To be clear, this means leaving the text entry cursor alone, unless it would be outside the [0, newlength] range, in which case it gets clamped?

  4. bzbarsky commented on Mar 8, 2017

    @bzbarsky
    ContributorAuthor

    Yes, exactly. Probably the same thing for selection too.

    So basically, adjust selectionStart/selectionEnd to min(currentValue,newLength).

  5. bzbarsky commented on Mar 8, 2017

    @bzbarsky
    ContributorAuthor

    One other problem: it's not clear to me what should happen when the control is focused, or maybe "has been focused". In that case, setting defaultValue seems to put the cursor at the end of the value in browsers? Not sure which parts here are interoperable, exactly.

  6. tkent-google commented on Mar 9, 2017

    @tkent-google
    Contributor

    I recently filed related issues:
    #2411
    #2412

    1. In Chrome, var x = document.createElement(tag); x.defaultValue = "abc"; alert(x.selectionStart); will alert 0 if tag is "input" but 3 if tag is "textarea".

    This behavior is definitely a bug. Chrome doesn't update selection values for input/defaultValue change at all. selectionStart and selectionEnd can be out of range. Oops.

    1. The initial state of the text entry cursor is at the beginning of the text control. The web depends on this behavior, looks like;

    I agree if this is already interoperable.

    1. Setting .value moves the text entry cursor to the end.

    Agree. This is defined and interoperable.

    1. Anything else that modifies a value just ensures that the text entry cursor is at some position in the range [0, newlength], clamping it to end as needed.

    I think in many cases modifying a value sets the cursor at the end of the text. At least updating textarea/@DefaultValue sets it to the end in all major browsers.

  7. bzbarsky commented on Mar 9, 2017

    @bzbarsky
    ContributorAuthor

    I agree if this is already interoperable.

    It's complicated. In particular there's ok interop for text controls that come from the parser, I think. But if you try to create one from script, you have to do the equivalent of setting .defaultValue, and suddenly implementations are all over the map per above.

    Agree. This is defined and interoperable.

    Though #2412 is proposing changing it a bit, right?

    I think in many cases modifying a value sets the cursor at the end of the text.

    Right, setting .value needs to do that per current spec. The question is about value changes that don't set .value but do change the value it returns.

    Most obviously, modifying the value via setRangeText or the user typing or whatnot obviously don't move the cursor. It's not clear how .defaultValue sets should behave. What about reset() calls? Direct mutations to the .nodeValue of a child of a textarea? Might be worth testing what UAs do in practice...

    At least updating textarea/@DefaultValue sets it to the end in all major browsers

    That's only sometimes true in Firefox. I'm pretty sure it's false if the textarea is display:none, for example, or not attached to a document...

    It's definitely false in Safari, unless I messed something up testing. See my first comment in this issue.

  8. bzbarsky commented on Mar 9, 2017

    @bzbarsky
    ContributorAuthor

    At least updating textarea/@DefaultValue sets it to the end in all major browsers

    As noted in https://bugzilla.mozilla.org/show_bug.cgi?id=1345293#c0 this is not necessarily true even in Chrome, depending on what "updating" means....

  9. bzbarsky commented on Mar 13, 2017

    @bzbarsky
    ContributorAuthor
  10. self-assigned this
    on Mar 14, 2017
  11. domenic commented on Mar 14, 2017

    @domenic
    Member

    I've posted #2437 and web-platform-tests/wpt#5147 around the first of these bugs, #2412, as that seems rather separable. But this and #2411 seem worth solving together; #2411 is largely a subset of the larger question posed here about what happens if the underlying value is changed, somehow.

    @bzbarsky's plan in #2424 (comment) still seems sound as a way forward, modulo the change in #2437 to not set selection to the end if the value is the same. However the big question for me is how to spec it. We could either have something vague, like "whenever the value changes, run these steps", or we could try to find all the places that update the value. We'll need to do the latter for tests anyway. So far what I've got are:

    • Setting the defaultValue attribute, sometimes (depending on the dirty value flag IIRC)
    • Setting the value attribute
    • Setting textContent on textareas, sometimes (depending on dirty value flag).
    • Otherwise modifying child nodes of textareas in a way that would cause textContent to change (if dirty vale flag is set)
    • setRangeText()
    • The reset algorithm
    • Users typing

    I guess from this perspective a vague "whenever the value changes" makes more sense.

    For textareas, there's also a difference between changing the element's value and its raw value. It seems like we only care about changes to value; e.g. if you set the raw value to "hell\r\no", then set it to "hell\no", that should not change selection. That's the assumption I made in #2437 at least.

  12. bzbarsky commented on Mar 15, 2017

    @bzbarsky
    ContributorAuthor

    I guess from this perspective a vague "whenever the value changes" makes more sense.

    You missed a few. Off the top of my head:

    • Browser form autofill.
    • Clipboard operations (paste, cut).
    • IME commit.
    • Form state restoration on history traversal.
    • Cloning steps, for the new clone.
    • Initial element creation.

    You'd think some of these would be covered by your list, but at least Blink has different behavior for foo.innerHTML = "<input value='something'>" and var i = document.createElement("input"); i.setAttribute("value", "something"); foo.appendChild(i);: the former puts the cursor at the start, and the latter puts it at the end...

    For textareas, there's also a difference between changing the element's value and its raw value.

    Right. I'm not sure how these interact with selection in practice. Is the selection in the raw value or in the value?

  13. bzbarsky commented on Mar 15, 2017

    @bzbarsky
    ContributorAuthor

    Oh, and I think it's obvious that paste/cut should probably not modify selection/cursor stuff in any ways other than the obvious one.... But at this point it would merely sadden me, not surprise me, to discover that we have no interop there either...

  14. domenic commented on Mar 15, 2017

    @domenic
    Member

    You missed a few. Off the top of my head:

    Sounds good. I'll try to add those to the test cases.

    Right. I'm not sure how these interact with selection in practice. Is the selection in the raw value or in the value?

    I imagine it should be on something with normalized line breaks (so value or API value) since you can't select the \r part of \r\n. I guess API value is the best fit there, hmm. But for determining changes either version with normalized line breaks works, see comment thread at #2437 (comment)

  15. 32 remaining items

  16. emanchado commented on Feb 27, 2018

    @emanchado

    Ok, see different approach in the branch selection-and-cursor-processing-input-textarea (commit 852ec69). Sorry for the delay, I've been busy.

    It's obviously incomplete, but I seem to be getting better results:

    • The first two tests (for defaultValue) behave differently in Firefox and Chrome.
    • The color type switching test fails in both (in different ways, too). I wonder if this has defined behaviour and/or it's important.

    Comments welcome. If this looks good now, I'll keep going and will try to cover all the mentioned cases.

  17. added a commit that references this issue on May 18, 2025
    3d2719a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

interopImplementations are not interoperable with each othertopic: forms

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions