diff --git a/packages/react-dom-bindings/src/client/ReactDOMInput.js b/packages/react-dom-bindings/src/client/ReactDOMInput.js index b6e665e128836..977d814ec9d52 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMInput.js +++ b/packages/react-dom-bindings/src/client/ReactDOMInput.js @@ -474,13 +474,18 @@ export function setDefaultValue( type: ?string, value: ToStringValue, ) { + const stringValue = toString(value); if ( // Focused number inputs synchronize on blur. See ChangeEventPlugin.js + // However, if the defaultValue has actually changed, we need to update it + // even for focused number inputs to ensure the visual value is properly updated + // after form actions complete. type !== 'number' || - getActiveElement(node.ownerDocument) !== node + getActiveElement(node.ownerDocument) !== node || + node.defaultValue !== stringValue ) { - if (node.defaultValue !== toString(value)) { - node.defaultValue = toString(value); + if (node.defaultValue !== stringValue) { + node.defaultValue = stringValue; } } } diff --git a/packages/react-dom/src/__tests__/ReactDOMInput-test.js b/packages/react-dom/src/__tests__/ReactDOMInput-test.js index 04bd96fe2e83e..f1e92bd2cfdab 100644 --- a/packages/react-dom/src/__tests__/ReactDOMInput-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMInput-test.js @@ -3109,4 +3109,51 @@ describe('ReactDOMInput', () => { expect(log).toEqual(['']); expect(node.value).toBe('a'); }); + + it('should update defaultValue for focused number inputs when value changes', async () => { + // This test reproduces the issue described in: + // https://github.com/facebook/react/issues/33667 + // Bug: input type number ignores defaultValue after clicking Enter when used with useActionState + + const TestComponent = () => { + const [state, setState] = React.useState({ value: '123' }); + + return ( +
+ { + if (e.key === 'Enter') { + // Simulate form action completion that updates state + setState({ value: '456' }); + } + }} + /> +
+ ); + }; + + await act(() => { + root.render(); + }); + + const node = container.firstChild; + expect(node.defaultValue).toBe('123'); + expect(node.value).toBe('123'); + + // Focus the input and type something + node.focus(); + setUntrackedValue.call(node, '789'); + dispatchEventOnNode(node, 'input'); + + // Simulate pressing Enter (which would trigger a form action) + const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' }); + node.dispatchEvent(enterEvent); + + // The defaultValue should be updated even though the input is focused + expect(node.defaultValue).toBe('456'); + // The visual value should also be updated + expect(node.value).toBe('456'); + }); });