Consider this testcase:
<!DOCTYPE html>
<pre><script>
var t = document.createElement("textarea");
t.appendChild(document.createElement("span")).appendChild(document.createTextNode("TEXT"));
document.body.appendChild(t);
document.writeln("textContent: " + t.textContent);
document.writeln("defaultValue: " + t.defaultValue);
document.writeln("value: " + t.value);
</script>
</pre>
Per spec, https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-defaultvalue is supposed to return the value of the textContent IDL attr, and per https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:textcontent the raw value is supposed to match the textContent if the dirty flag is false. So per spec as currently written, all three of textContent, defaultValue, value should be "TEXT", and I would think that "TEXT" should appear in the textarea.
Actual observed behavior is:
Live testcase: https://jsfiddle.net/t9dz1zyj/1/
It looks like Edge is generally pretty buggy on this defaultValue business; the testcase at https://jsfiddle.net/t9dz1zyj/2/ shows "TEXT" for all three properties in Gecko/Blink/WebKit, and should per current spec, but still shows empty defaultValue in Edge...
Anyway, it looks like Edge is trying to do what the spec says, modulo its defaultValue bug. I know for a fact (code inspection) Gecko only considers direct child textnodes for its default value for textarea. Looks like Blink does the same. I'm really not sure what WebKit is doing.
//cc @domenic @travisleithead
the testcase at https://jsfiddle.net/t9dz1zyj/2/
That's
<!DOCTYPE html>
<pre><script>
var t = document.createElement("textarea");
t.textContent = "TEXT";
document.body.appendChild(t);
document.writeln("textContent: " + t.textContent);
document.writeln("defaultValue: " + t.defaultValue);
document.writeln("value: " + t.value);
</script>
</pre>
Combined with https://github.com/whatwg/html/issues/2750 and the related selection bugs, I'm becoming convinced that everything is pretty broken around the textarea spec.
Do you have a suggestion for a reasonable model we could try to converge everyone on, ideally solving both this issue and #2750? And maybe https://github.com/whatwg/html/issues/2424 as well (cf. https://github.com/whatwg/html/issues/2424#issuecomment-286580627)
Well, the good news is that Gecko and Blink seem to have interop for purposes of this issue.
The conceptual model in Gecko is as follows:
There are some complications in terms of what happens if you do these things before the parser is actually done parsing the textarea, though I'm not 100% sure whether that's even a situation you can get into in practice (do we ever insert the textarea into the DOM before we finish parsing its content in a way such that we can end up waiting on network for a bit there and run user script?).
The actual implementation of the Gecko behavior is as follows:
defaultValue getter.defaultValue getter only considers immediate child textnodes.So in practice we're not storing the "default value" in any form other than the actual DOM subtree under the textarea.
OK, great. It sounds like the majority of spec work here will be specifying the "something that would affect textContent". I think my plan would be:
I think Gecko and Blink behavior, concatenating Text children, is reasonable. If TEXTAREA needs to react to any textContent change, DOM mutation operations need to be notified to all of TEXTAREA ancestors, and it would slow down DOM mutation without TEXTAREA too.
WebKit's behavior is almost same as Gecko and Blink internally. It just returns textContent for defaultValue IDL attribute getter.
Hmm, I skimmed over the difference between textContent and contenation of immediately child text nodes. The spec currently leans hard on the connection to textContent, e.g.
The reset algorithm for textarea elements is to set the dirty value flag back to false, and set the raw value of element to the value of the element's textContent IDL attribute.
It sounds like we can match Firefox/Chrome by converging away from textContent to the concatenation of child text nodes.
Here is my proposed spec text, replacing a few existing paragraphs (Ctrl+F for "textContent" in the textarea section of the spec):
A textarea element has the following child text changed steps:
[child text changed and child text are defined as you would expect, in DOM I guess.]
The reset algorithm for textarea elements is to set the dirty value flag to false, and set the raw value of element to its child text.
If the textarea element has a maximum allowed value length, then the element's children must be such that the JavaScript string length of the value of the element's textContent IDL attribute with the textarea line break normalization transformation applied is equal to or less than the element's maximum allowed value length. [no change; this is a conformance requirement on authors who should not be inserting child elements into textarea elements]
The defaultValue IDL attribute must return the element's child text.
Does this sound good to you, @bzbarsky and @tkent-google? @cdumez might enjoy this as well, as even though Safari doesn't match the proposal/Firefox/Blink, it also doesn't match the current spec.
That sounds reasonable to me. We should really check with Microsoft, since they're the closest to what the current spec says, though still not matching it.
https://html.spec.whatwg.org/#child-text-content is a concept the spec has already for a bunch of things, FWIW.
Is there a web compat need to flip the dirty flag if textContent changes but "child text content" doesn't? Is that hook used for anything other than textarea? I'm wondering if it's possible (and if there's interest) to make this simpler and basically only consider the children of textarea.
cc @travisleithead
Is there a web compat need to flip the dirty flag if textContent changes but "child text content" doesn't?
I don't follow. The dirty flag is never changed by changes to either "textContent" or "child text content". What those changes do is, if the dirty flag is _not_ set, set the raw value to the "child text content" (or "textContent", in current spec). They do NOT affect the dirty flag.
Ok, sorry, I was clearly confused.
So if the dirty flag is not set, can we not set the raw value when non-child descendants change?
That is the proposal, yes.
Though as long as we set it to "child text content", it doesn't matter whether we do it when only kids change or when non-child descendants change, right? The observables are the same.
I seem to have lost a step in my above set, which does nothing if the dirty value flag is true. I edited to add that. That might be causing some of the confusion.