diff --git a/packages/react-dom/src/__tests__/ReactDOMInput-test.js b/packages/react-dom/src/__tests__/ReactDOMInput-test.js
index f5513557ec3c0..ccd71ee4dcba8 100644
--- a/packages/react-dom/src/__tests__/ReactDOMInput-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMInput-test.js
@@ -1700,4 +1700,32 @@ describe('ReactDOMInput', () => {
expect(node.hasAttribute('value')).toBe(false);
});
});
+
+ describe('use empty value with input button', function() {
+ it('should not set a value when value is empty', () => {
+ let stub = ;
+ stub = ReactTestUtils.renderIntoDocument(stub);
+ const node = ReactDOM.findDOMNode(stub);
+
+ expect(node.hasAttribute('value')).toBe(false);
+ });
+
+ it('should remove value when value is empty', () => {
+ class Input extends React.Component {
+ state = {type: 'submit', value: 'foo'};
+
+ render() {
+ const {value, type} = this.state;
+ return {}} type={type} value={value} />;
+ }
+ }
+
+ const input = ReactTestUtils.renderIntoDocument();
+ const node = ReactDOM.findDOMNode(input);
+
+ expect(node.getAttribute('value')).toBe('foo');
+ input.setState({value: undefined});
+ expect(node.hasAttribute('value')).toBe(false);
+ });
+ });
});
diff --git a/packages/react-dom/src/client/ReactDOMFiberInput.js b/packages/react-dom/src/client/ReactDOMFiberInput.js
index fd5a574fec377..1268aa021d5e8 100644
--- a/packages/react-dom/src/client/ReactDOMFiberInput.js
+++ b/packages/react-dom/src/client/ReactDOMFiberInput.js
@@ -35,8 +35,21 @@ let didWarnControlledToUncontrolled = false;
let didWarnUncontrolledToControlled = false;
function isControlled(props) {
- const usesChecked = props.type === 'checkbox' || props.type === 'radio';
- return usesChecked ? props.checked != null : props.value != null;
+ if (props.type === 'checkbox' || props.type === 'radio') {
+ return props.checked != null;
+ } else if (props.type === 'submit' || props.type === 'reset') {
+ return props.hasOwnProperty('value');
+ } else {
+ return props.value != null;
+ }
+}
+
+function isEmptyValueButton(props) {
+ if (props.type !== 'submit' && props.type !== 'reset') {
+ return false;
+ }
+
+ return props.value === undefined || props.value === null;
}
/**
@@ -194,7 +207,9 @@ export function updateWrapper(element: Element, props: Object) {
}
}
- if (props.hasOwnProperty('value')) {
+ if (isEmptyValueButton(props)) {
+ node.removeAttribute('value');
+ } else if (props.hasOwnProperty('value')) {
setDefaultValue(node, props.type, value);
} else if (props.hasOwnProperty('defaultValue')) {
setDefaultValue(node, props.type, getSafeValue(props.defaultValue));
@@ -208,7 +223,10 @@ export function updateWrapper(element: Element, props: Object) {
export function postMountWrapper(element: Element, props: Object) {
const node = ((element: any): InputWithWrapperState);
- if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) {
+ if (
+ !isEmptyValueButton(props) &&
+ (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue'))
+ ) {
// Do not assign value if it is already set. This prevents user text input
// from being lost during SSR hydration.
if (node.value === '') {