diff --git a/src/renderers/dom/client/wrappers/ReactDOMInput.js b/src/renderers/dom/client/wrappers/ReactDOMInput.js index 682a34961a..039cadc5e0 100644 --- a/src/renderers/dom/client/wrappers/ReactDOMInput.js +++ b/src/renderers/dom/client/wrappers/ReactDOMInput.js @@ -67,7 +67,11 @@ var ReactDOMInput = { var value = LinkedValueUtils.getValue(props); var checked = LinkedValueUtils.getChecked(props); - var nativeProps = assign({}, props, { + var nativeProps = assign({ + // Make sure we set .type before any other properties (setting .value + // before .type means .value is lost in IE11 and below) + type: undefined, + }, props, { defaultChecked: undefined, defaultValue: undefined, value: value != null ? value : inst._wrapperState.initialValue, diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js index ffa90a059d..09d4772e91 100644 --- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js +++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js @@ -414,4 +414,32 @@ describe('ReactDOMInput', function() { ReactTestUtils.renderIntoDocument(); expect(console.error.argsForCall.length).toBe(1); }); + + it('sets type before value always', function() { + var log = []; + var originalCreateElement = document.createElement; + spyOn(document, 'createElement').andCallFake(function(type) { + var el = originalCreateElement.apply(this, arguments); + if (type === 'input') { + Object.defineProperty(el, 'value', { + get: function() {}, + set: function() { + log.push('set value'); + }, + }); + spyOn(el, 'setAttribute').andCallFake(function(name, value) { + log.push('set ' + name); + }); + } + return el; + }); + + ReactTestUtils.renderIntoDocument(); + // Setting value before type does bad things. Make sure we set type first. + expect(log).toEqual([ + 'set data-reactroot', + 'set type', + 'set value', + ]); + }); });