
React19 Source Patterns
Install react19-source-patterns when upgrading or auditing a React app so createRoot/hydrateRoot and removed APIs are migrated with copy-paste before/after patterns.
Overview
react19-source-patterns is an agent skill most often used in Build (also Ship) that supplies before/after React 19 migration snippets for roots, hydration, and removed DOM APIs.
Install
npx skills add https://github.com/github/awesome-copilot --skill react19-source-patternsWhat is this skill?
- createRoot() migration from ReactDOM.render for CSR apps
- hydrateRoot() replacement for ReactDOM.hydrate on SSR/static apps
- unmountComponentAtNode removed—patterns to retain root references for root.unmount()
- findDOMNode() removal with ref-forwarding replacements
- Verification note when React 18 migration already applied
Adoption & trust: 693 installs on skills.sh; 34.6k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your React app still uses ReactDOM.render, hydrate, findDOMNode, or unmountComponentAtNode and breaks or warns after moving to React 19.
Who is it for?
Indie SaaS or extension frontends on React 18-era bootstraps who need a fast, accurate API diff while upgrading dependencies.
Skip if: Greenfield React 19 apps already on createRoot, or backends/API-only repos with no React client bundle.
When should I use this skill?
Upgrading a React codebase to React 19 or fixing compiler/test errors from removed ReactDOM APIs.
What do I get? / Deliverables
Entry files and legacy components are updated to createRoot/hydrateRoot and ref-based DOM access patterns that match React 19 requirements.
- Updated entry and component files matching React 19 root APIs
- List of remaining legacy API call sites to fix
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
React 19 breaking changes are fixed while building or refactoring the UI codebase—the primary shelf is Build → frontend where roots and legacy APIs live. Frontend subphase covers client render entrypoints, hydration, and component APIs that break on the React 19 upgrade path.
Where it fits
Rewrite index.tsx to use createRoot after bumping react-dom to 19.x.
Scan the repo for remaining findDOMNode imports before merging a major React upgrade PR.
How it compares
Curated migration snippets for React 19—not a framework scaffold or a replacement for the official React codemods docs alone.
Common Questions / FAQ
Who is react19-source-patterns for?
react19-source-patterns is for developers shipping React UIs who are upgrading from React 18 patterns and want agent-guided, source-level replacements for removed APIs.
When should I use react19-source-patterns?
Use it during Build frontend upgrades when editing main.tsx or _app entrypoints, and during Ship review when tests fail on deprecated ReactDOM calls.
Is react19-source-patterns safe to install?
It is reference documentation for code changes; review the Security Audits panel on this page and validate migrations with your test suite before deploying.
SKILL.md
READMESKILL.md - React19 Source Patterns
# React 19 API Migrations Reference Complete before/after patterns for all React 19 breaking changes and removed APIs. --- ## ReactDOM Root API Migration React 19 requires `createRoot()` or `hydrateRoot()` for all apps. If the React 18 migration already ran, this is done. Verify it's correct. ### Pattern 1: createRoot() CSR App ```jsx // Before (React 18 or earlier): import ReactDOM from 'react-dom'; ReactDOM.render(<App />, document.getElementById('root')); // After (React 19): import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')); root.render(<App />); ``` ### Pattern 2: hydrateRoot() SSR/Static App ```jsx // Before (React 18 server-rendered app): import ReactDOM from 'react-dom'; ReactDOM.hydrate(<App />, document.getElementById('root')); // After (React 19): import { hydrateRoot } from 'react-dom/client'; hydrateRoot(document.getElementById('root'), <App />); ``` ### Pattern 3: unmountComponentAtNode() Removed ```jsx // Before (React 18): import ReactDOM from 'react-dom'; ReactDOM.unmountComponentAtNode(container); // After (React 19): const root = createRoot(container); // Save the root reference // later: root.unmount(); ``` **Caveat:** If the root reference was never saved, you must refactor to pass it around or use a global registry. --- ## findDOMNode() Removed ### Pattern 1: Direct ref ```jsx // Before (React 18): import { findDOMNode } from 'react-dom'; const domNode = findDOMNode(componentRef); // After (React 19): const domNode = componentRef.current; // refs point directly to DOM ``` ### Pattern 2: Class Component ref ```jsx // Before (React 18): import { findDOMNode } from 'react-dom'; class MyComponent extends React.Component { render() { return <div ref={ref => this.node = ref}>Content</div>; } getWidth() { return findDOMNode(this).offsetWidth; } } // After (React 19): // Note: findDOMNode() is removed in React 19. Eliminate the call entirely // and use direct refs to access DOM nodes instead. class MyComponent extends React.Component { nodeRef = React.createRef(); render() { return <div ref={this.nodeRef}>Content</div>; } getWidth() { return this.nodeRef.current.offsetWidth; } } ``` --- ## forwardRef() - Optional Modernization ### Pattern 1: Function Component Direct ref ```jsx // Before (React 18): import { forwardRef } from 'react'; const Input = forwardRef((props, ref) => ( <input ref={ref} {...props} /> )); function App() { const inputRef = useRef(null); return <Input ref={inputRef} />; } // After (React 19): // Simply accept ref as a regular prop: function Input({ ref, ...props }) { return <input ref={ref} {...props} />; } function App() { const inputRef = useRef(null); return <Input ref={inputRef} />; } ``` ### Pattern 2: forwardRef + useImperativeHandle ```jsx // Before (React 18): import { forwardRef, useImperativeHandle } from 'react'; const TextInput = forwardRef((props, ref) => { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => inputRef.current.focus(), clear: () => { inputRef.current.value = ''; } })); return <input ref={inputRef} {...props} />; }); function App() { const textRef = useRef(null); return ( <> <TextInput ref={textRef} /> <button onClick={() => textRef.current.focus()}>Focus</button> </> ); } // After (React 19): function TextInput({ ref, ...props }) { const inputRef = useRef(null); useImperativeHandle(ref, () => ({ focus: () => inputRef.current.focus(), clear: () => { inputRef.current.value = ''; } })); return <input ref={inputRef} {...props} />; } function App() { const textRef = useRef(null); return ( <> <TextInput ref={textRef} /> <button onClick={() => textRef.current.focus()}>Focus</button> </> ); } ``` **Note:** `useImperativeHandle` is still valid; only the `forwardRe