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',
+ ]);
+ });
});