React 19 in WordPress is still coming, but Gutenberg rolled it back within days of shipping it. Version 23.3.0 upgraded the editor runtime to React 19, plugins built against React 18 started crashing in the editor, and the team reverted to React 18 in 23.3.2 while it plans a slower path into WordPress 7.1. The revert note on Make WordPress Core by Jarda Snajdr is short, and the failure it describes matters to anyone who ships JavaScript into wp-admin, React or not.
What React 19 in WordPress broke
Almost nothing in the public API changed between the two versions, which is why the crash caught people out. The internals did. Plenty of plugins bundle their own copy of react/jsx-runtime, the small helper the automatic JSX transform uses to create elements. React 19 gives that helper a different element shape, and it also checks the elements it renders and rejects the ones produced by the React 18 helper. Your plugin still compiles and loads fine, and then core’s React 19 renderer refuses the elements it hands over. On a client site that looks like an editor that fails to load or a plugin panel that dies, with a React error in the console pointing at the mismatch.
The active rejection is a deliberate choice on React’s side, and I think it is the right one, because bugs fail loudly instead of quietly. The cost of that loudness is this rollback: every plugin that froze the old element shape inside its build breaks at the same moment. The React 19 upgrade guide covers the API and typing changes, but it cannot prepare you for two runtime copies meeting on one page.
Bundle your own React or use the copy core ships
This incident comes down to a choice between two build strategies. Option one is to treat React as an external and depend on core’s script handles. Your build stays small, one renderer lives on the page, and when core upgrades React your plugin rides along. The flip side is that core’s schedule becomes your schedule, which is what just bit everyone.
Option two is to bundle React and jsx-runtime into your own build file. It is self-contained and works on any host, but you are shipping a second React into a page that already has one, and that is the setup that crashed. Two renderers can coexist if they never exchange elements, and admin screens exchange elements constantly through slots, portals and shared modals.
For distributed plugins my pick is always core’s handles, and that is what I wrote when the upgrade was first announced. For a one-off client tool I still default to core’s copy, because the admin already runs React and a second runtime buys nothing. The only case where bundling makes sense is a fully isolated settings page that mounts its own root and never touches Gutenberg packages, and even then you pay the payload on every load.
If you build with @wordpress/scripts, recent versions already treat react, react-dom and react/jsx-runtime as externals, so for most plugins the fix is small. Core has registered a react-jsx-runtime handle for a while now, so declare it as a dependency and let the bundler point at core’s copy:
wp_enqueue_script(
'bbioon_editor_panel',
plugins_url( 'build/index.js', __FILE__ ),
array( 'wp-plugins', 'wp-element', 'react-jsx-runtime' ),
'1.0.0',
true
);
To find out whether an existing plugin bundles its own runtime, open its build file and search for the literal string react.element. Compiled React contains it (it is the symbol fallback), so if your build has it, you are carrying a second copy. I would run that grep across every custom plugin on a site now rather than after the 7.1 upgrade.
The plan, per the revert post, is an experimental flag to switch between React 18 and 19 plus a compat layer for plugins already released, with the upgrade still targeted at WordPress 7.1. In the comments BlackStar asked for React 19 checks in Plugin Check and Anh Tran asked for migration docs, and both would help. I am not sure how far a compat layer can stretch when the rejection happens inside React itself, but the flag alone makes testing realistic. The checks I run before updating Gutenberg cover most of what you would do with it.
On a client site this week I would get to Gutenberg 23.3.2 or newer, run that react.element grep across the custom plugins, and add the react-jsx-runtime dependency wherever it is missing. If you maintain editor plugins and want that audit done properly, this is the kind of work I take on, so send your plugin list over.