From 7d93467e1d6892b7f3819ced536f28b3abf2e05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo=20Soares=20Bispo?= Date: Tue, 28 Apr 2026 21:37:22 -0300 Subject: [PATCH] Add writingsuggestions as a recognized booleanish attribute Add writingsuggestions as a recognized booleanish attribute `writingsuggestions` is a global HTML attribute that controls whether the browser offers writing suggestions (autocorrect, autocomplete, etc.). It is an enumerated attribute accepting "true" and "false", similar to `draggable` and `spellCheck`. Previously, passing `writingsuggestions={false}` would silently remove the attribute from the DOM. Now it correctly sets the attribute to the string "false". --- .../src/client/ReactDOMComponent.js | 2 ++ .../src/server/ReactFizzConfigDOM.js | 1 + .../src/shared/ReactDOMUnknownPropertyHook.js | 1 + .../src/shared/possibleStandardNames.js | 1 + .../src/__tests__/ReactDOMComponent-test.js | 36 +++++++++++++++++++ ...eactDOMServerIntegrationAttributes-test.js | 12 +++++++ 6 files changed, 53 insertions(+) diff --git a/packages/react-dom-bindings/src/client/ReactDOMComponent.js b/packages/react-dom-bindings/src/client/ReactDOMComponent.js index 80ee96a87a8f..ad8d15b09aff 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMComponent.js +++ b/packages/react-dom-bindings/src/client/ReactDOMComponent.js @@ -708,6 +708,7 @@ function setProp( case 'contentEditable': case 'spellCheck': case 'draggable': + case 'writingsuggestions': case 'value': case 'autoReverse': case 'externalResourcesRequired': @@ -2831,6 +2832,7 @@ function diffHydratedGenericElement( continue; } case 'draggable': + case 'writingsuggestions': case 'autoReverse': case 'externalResourcesRequired': case 'focusable': diff --git a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js index 691e49e563fd..6de0ab6170c6 100644 --- a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js +++ b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js @@ -1656,6 +1656,7 @@ function pushAttribute( case 'contentEditable': case 'spellCheck': case 'draggable': + case 'writingsuggestions': case 'value': case 'autoReverse': case 'externalResourcesRequired': diff --git a/packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js b/packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js index aee7d9adb7df..66970646b58f 100644 --- a/packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js +++ b/packages/react-dom-bindings/src/shared/ReactDOMUnknownPropertyHook.js @@ -199,6 +199,7 @@ function validateProperty(tagName, name, value, eventRegistry) { case 'contentEditable': case 'spellCheck': case 'draggable': + case 'writingsuggestions': case 'value': case 'autoReverse': case 'externalResourcesRequired': diff --git a/packages/react-dom-bindings/src/shared/possibleStandardNames.js b/packages/react-dom-bindings/src/shared/possibleStandardNames.js index e111c097c75b..394a4b70adb2 100644 --- a/packages/react-dom-bindings/src/shared/possibleStandardNames.js +++ b/packages/react-dom-bindings/src/shared/possibleStandardNames.js @@ -162,6 +162,7 @@ const possibleStandardNames = { width: 'width', wmode: 'wmode', wrap: 'wrap', + writingsuggestions: 'writingsuggestions', // SVG about: 'about', diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index 824541bb2d80..3d09287afaa3 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -2688,6 +2688,16 @@ describe('ReactDOMComponent', () => { ]); }); + it('should warn about incorrect casing on the writingsuggestions property (ssr)', () => { + ReactDOMServer.renderToString( + React.createElement('div', {WritingSuggestions: 'false'}), + ); + assertConsoleErrorDev([ + 'Invalid DOM property `WritingSuggestions`. Did you mean `writingsuggestions`?\n' + + ' in div (at **)', + ]); + }); + it('should warn about incorrect casing on event handlers (ssr)', () => { ReactDOMServer.renderToString( React.createElement('input', {type: 'text', oninput: '1'}), @@ -3615,6 +3625,32 @@ describe('ReactDOMComponent', () => { expect(el.getAttribute('spellCheck')).toBe('true'); }); + + it('stringifies the boolean true for writingsuggestions', async function () { + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + await act(() => { + root.render(
); + }); + + const el = container.firstChild; + + expect(el.getAttribute('writingsuggestions')).toBe('true'); + }); + + it('stringifies the boolean false for writingsuggestions', async function () { + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + await act(() => { + root.render(
); + }); + + const el = container.firstChild; + + expect(el.getAttribute('writingsuggestions')).toBe('false'); + }); }); describe('Boolean attributes', function () { diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js index 9857718c35b7..4ad3d7542216 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js @@ -199,6 +199,18 @@ describe('ReactDOMServerIntegration', () => { }); }); + describe('writingsuggestions property', function () { + itRenders('writingsuggestions prop with true value', async render => { + const e = await render(
); + expect(e.getAttribute('writingsuggestions')).toBe('true'); + }); + + itRenders('writingsuggestions prop with false value', async render => { + const e = await render(
); + expect(e.getAttribute('writingsuggestions')).toBe('false'); + }); + }); + describe('download property (combined boolean/string attribute)', function () { itRenders('download prop with true value', async render => { const e = await render();