---
# === IDENTITY ===
id: software/migrations/angularjs-to-react/2026
canonical_question: "How do I migrate from AngularJS to React?"
aliases:
  - "AngularJS to React migration guide"
  - "convert AngularJS to React"
  - "replace AngularJS with React"
  - "AngularJS 1.x to React migration"
  - "modernize AngularJS app with React"
  - "incremental AngularJS to React"
entity_type: software_reference
domain: software > migrations > angularjs_to_react
region: global
jurisdiction: global
temporal_scope: 2016-2026

# === VERIFICATION ===
last_verified: 2026-05-17
confidence: 0.93
version: 2.1
first_published: 2026-02-17

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: evolving
  last_breaking_change: "CVE-2026-22610 (SVG XSS in template compiler) disclosed Jan 2026; CVE-2025-4690 / CVE-2025-2336 in ng-sanitize disclosed late 2025; Chrome 130+ removed synchronous XHR (breaks AngularJS bootstrap on uncached scripts)"
  next_review: 2026-11-13
  change_sensitivity: medium

# === CONSTRAINTS ===
constraints:
  - "AngularJS must be 1.5+ for react2angular bridge (component API required); for 1.2-1.4, use ngReact with directive bridge instead"
  - "Never attempt a big-bang rewrite on codebases > 5,000 LOC — use incremental migration to avoid halting feature delivery"
  - "Both AngularJS and React must share a single source of truth for state (Redux recommended) during migration — never duplicate state across frameworks"
  - "Replace the router last — it is the most disruptive step and forces all page components to be converted simultaneously"
  - "AngularJS is EOL since Dec 2021 with 10+ unpatched CVEs (including CVE-2026-22610 SVG-XSS, CVE-2025-4690 / CVE-2025-2336 in ng-sanitize, CVE-2024-21490 ng-srcset ReDoS) — PCI DSS 4.0 bans EOL frameworks without verified mitigation; migration is a compliance requirement, not optional"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "App is on Angular 2+ (modern Angular), not AngularJS 1.x"
    use_instead: "software/migrations/angular-to-react/2026"
  - condition: "Goal is to upgrade AngularJS to modern Angular (not React)"
    use_instead: "software/migrations/angularjs-to-angular/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: angularjs_version
    question: "What version of AngularJS is the app currently running?"
    type: choice
    options: ["1.2-1.4 (no component API)", "1.5-1.7 (component API)", "1.8.x (final release)"]
  - key: app_size
    question: "Approximately how many lines of code is the AngularJS application?"
    type: choice
    options: ["< 5,000 LOC (small)", "5,000-50,000 LOC (medium)", "> 50,000 LOC (large)"]
  - key: state_management
    question: "What state management does the AngularJS app currently use?"
    type: choice
    options: ["$scope/$rootScope only", "Services/factories with $scope", "Already using Redux/ngrx", "Custom event bus ($emit/$broadcast)"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/migrations/angularjs-to-react/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-05-17)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "software/migrations/javascript-to-typescript/2026"
      label: "JavaScript to TypeScript Migration Guide"
  solves: []
  alternative_to:
    - id: "software/migrations/angularjs-to-angular/2026"
      label: "AngularJS to Angular Migration Guide"
  often_confused_with:
    - id: "software/migrations/angular-to-react/2026"
      label: "Angular (2+) to React Migration Guide"

# === SOURCES (10 authoritative sources) ===
# Types: official_docs, technical_blog, rfc_spec, academic_paper, community_resource, industry_report
# Reliability: high, moderate_high, moderate, moderate_low, low, authoritative
sources:
  - id: src1
    title: "Integrating with Other Libraries"
    author: React (Meta)
    url: https://legacy.reactjs.org/docs/integrating-with-other-libraries.html
    type: official_docs
    published: 2023-03-01
    reliability: authoritative
  - id: src2
    title: "Our journey migrating 100k lines of code from AngularJS to React"
    author: Small Improvements
    url: https://tech.small-improvements.com/how-to-migrate-an-angularjs-1-app-to-react/
    type: technical_blog
    published: 2019-06-15
    reliability: high
  - id: src3
    title: "Migrating Angular 1.x apps to React — The Hybrid Way"
    author: Ankur Tiwari (Walmart Global Tech)
    url: https://medium.com/walmartglobaltech/migrating-angular-1-x-apps-to-react-the-hybrid-way-3267ccf33755
    type: technical_blog
    published: 2018-09-20
    reliability: high
  - id: src4
    title: "Incrementally Migrating From AngularJS to React"
    author: Hanna Liebl
    url: https://www.hannaliebl.com/blog/incrementally-migrating-from-angularjs-to-react/
    type: technical_blog
    published: 2022-01-10
    reliability: high
  - id: src5
    title: "Codebase Conversion: Migrating a MEAN AngularJS app to React, Next.js, and TypeScript"
    author: Mark Erikson
    url: https://blog.isquaredsoftware.com/2021/12/codebase-conversion-mean-react-next-ts/
    type: technical_blog
    published: 2021-12-15
    reliability: high
  - id: src6
    title: "react2angular — The easiest way to embed React components in Angular 1 apps"
    author: Coatue (coatue-oss)
    url: https://github.com/coatue-oss/react2angular
    type: community_resource
    published: 2023-01-01
    reliability: moderate_high
  - id: src7
    title: "The State of AngularJS in 2025"
    author: HeroDevs
    url: https://www.herodevs.com/blog-posts/the-state-of-angularjs-in-2025
    type: industry_report
    published: 2025-01-15
    reliability: high
  - id: src8
    title: "AngularJS 2026: Security, Compliance & Migration Guide"
    author: AvidClan
    url: https://www.avidclan.com/blog/angularjs-2026-security-migration-guide/
    type: industry_report
    published: 2026-01-10
    reliability: high
  - id: src9
    title: "CVE-2026-22610: XSS Vulnerability in Angular Template Compiler via Unsanitized SVG Script Attributes"
    author: HeroDevs Security Research
    url: https://www.herodevs.com/blog-posts/cve-2026-22610-xss-vulnerability-in-angular-template-compiler-via-unsanitized-svg-script-attributes
    type: industry_report
    published: 2026-01-22
    reliability: high
  - id: src10
    title: "AngularJS Never-Ending Support (NES) — Drop-in patches for EOL AngularJS"
    author: HeroDevs
    url: https://www.herodevs.com/support/nes-angularjs
    type: industry_report
    published: 2026-04-01
    reliability: high
---

# How to Migrate from AngularJS to React

## TL;DR

- **Bottom line**: Use an incremental, bottom-up migration strategy with `react2angular` to embed React components inside your AngularJS app, converting leaf components first and working up the component tree until AngularJS can be fully removed. [src2, src4]
- **Key tool/command**: `npm install react2angular react react-dom prop-types` — the bridge library that lets React components be used as AngularJS directives [src6]
- **Watch out for**: Attempting a full rewrite instead of incremental migration — this is the #1 cause of failed migrations, as it halts feature development and introduces massive risk. [src2, src5]
- **Works with**: AngularJS 1.5+ (component API required for `react2angular`), React 16.8+ (hooks), React 18.x (with `react18-react2angular` fork), React 19.x (test bridge compatibility). [src6]

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- AngularJS must be 1.5+ for `react2angular` bridge (component API required); for 1.2-1.4, use `ngReact` with directive bridge instead [src6]
- Never attempt a big-bang rewrite on codebases > 5,000 LOC — use incremental migration to avoid halting feature delivery [src2, src5]
- Both AngularJS and React must share a single source of truth for state (Redux recommended) during migration — never duplicate state across frameworks [src4, src5]
- Replace the router last — it is the most disruptive step and forces all page components to be converted simultaneously [src4]
- AngularJS is EOL since Dec 2021 with 10+ unpatched CVEs (including CVE-2026-22610 SVG-XSS in template compiler, CVE-2025-4690 and CVE-2025-2336 in ng-sanitize, CVE-2024-21490 ng-srcset ReDoS, CVE-2024-8372, CVE-2024-8373) — PCI DSS 4.0 bans EOL frameworks without verified mitigation; FedRAMP/EO 14028 SBOM requirements flag EOL components as major NIST 800-53 CM-8 deficiencies. Migration is a compliance requirement, not optional. [src8, src9, src10]

## Quick Reference

| AngularJS Pattern | React Equivalent | Example |
|---|---|---|
| `$scope` / `$rootScope` | `useState` / `useContext` / Redux store | `const [count, setCount] = useState(0)` |
| `ng-model` (two-way binding) | Controlled component (`value` + `onChange`) | `<input value={val} onChange={e => setVal(e.target.value)} />` |
| `ng-repeat` | `Array.map()` in JSX | `{items.map(item => <Item key={item.id} {...item} />)}` |
| `ng-if` / `ng-show` | Conditional rendering / CSS class toggle | `{show && <Component />}` or `style={{display: show ? 'block' : 'none'}}` |
| `ng-click` | `onClick` handler | `<button onClick={handleClick}>Go</button>` |
| `ng-class` | `className` with template literal or `clsx` | `className={clsx('btn', {active: isActive})}` |
| Directive (restrict: 'E') | Functional component | `function MyWidget({ title }) { return <h2>{title}</h2>; }` |
| Service / Factory (DI) | Module import / Context / custom hook | `import { apiClient } from './services/api'` |
| `$http` / `$resource` | `fetch` / `axios` / React Query / TanStack Query | `const { data } = useQuery({ queryKey: ['users'], queryFn: fetchUsers })` |
| `$watch` / `$watchCollection` | `useEffect` with dependency array | `useEffect(() => { ... }, [value])` |
| `$timeout` / `$interval` | `setTimeout` / `setInterval` + `useEffect` cleanup | `useEffect(() => { const id = setInterval(fn, 1000); return () => clearInterval(id); }, [])` |
| `resolve` (route pre-fetch) | Loader function (React Router 6) / `useEffect` | `loader: async () => fetch('/api/data')` |
| Filters (`{{ val | currency }}`) | Helper functions called in JSX | `{formatCurrency(val)}` |
| `angular.module('app', [deps])` | ES module imports + `<App />` root | `import App from './App'; createRoot(el).render(<App />)` |
| `$emit` / `$broadcast` (event bus) | Callback props / Context / state management | `<Child onUpdate={handleUpdate} />` |

## Decision Tree

```
START
|-- Is your AngularJS app < 5,000 LOC?
|   |-- YES --> Consider a clean rewrite in React (faster than incremental migration)
|   +-- NO |
|-- Does your app use AngularJS 1.5+ component API?
|   |-- YES --> Use react2angular for bridge (see Step 2)
|   +-- NO |
|-- Does your app use only directives (restrict: 'E', 'A')?
|   |-- YES --> Use ngReact or angular2react for bridge (see Step 2, Alternative)
|   +-- NO |
|-- Is your app under active feature development?
|   |-- YES --> Incremental migration: new features in React, bridge existing (see Step-by-Step Guide)
|   +-- NO |
|-- Is the app in maintenance mode with security-only updates?
|   |-- YES --> Consider HeroDevs NES while planning migration [src7]
|   +-- NO |
|-- Is PCI DSS 4.0 or FedRAMP compliance required?
|   |-- YES --> Migrate urgently — EOL frameworks banned without verified mitigation [src8]
|   +-- NO |
+-- DEFAULT --> Incremental bottom-up migration with react2angular + shared Redux store [src2, src4]
```

## Step-by-Step Guide

### 1. Set up the React build pipeline alongside AngularJS

Add React and its build tooling to your existing project without removing any AngularJS code. Use your existing bundler (webpack, rollup) or add one if you only use script tags. [src1, src5]

```bash
# Install React core + bridge library
npm install react react-dom react2angular prop-types

# Install build tooling (if not already present)
npm install --save-dev @babel/preset-react webpack webpack-cli babel-loader

# For TypeScript projects
npm install --save-dev typescript @types/react @types/react-dom
```

Add JSX support to your webpack/babel config:

```javascript
// webpack.config.js — add to module.rules
{
  test: /\.(js|jsx|tsx?)$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env', '@babel/preset-react']
    }
  }
}
```

**Verify**: `npx webpack --mode development` builds without errors, and your existing AngularJS app still works unchanged.

### 2. Create the React-AngularJS bridge

Register React components as AngularJS directives using `react2angular`. This is the core mechanism that allows both frameworks to coexist. [src4, src6]

```javascript
// bridge.js — Register React components as Angular directives
import { react2angular } from 'react2angular';
import angular from 'angular';
import { UserCard } from './components/UserCard'; // your new React component

angular
  .module('myApp')
  .component('userCard', react2angular(UserCard, ['user', 'onEdit']));
// Props are passed as attributes: <user-card user="$ctrl.user" on-edit="$ctrl.handleEdit">
```

For apps using the older directive API instead of `.component()`, use `ngReact`:

```javascript
// Alternative: ngReact bridge for directive-based apps (AngularJS < 1.5)
import 'ngreact';
import { UserCard } from './components/UserCard';

angular
  .module('myApp', ['react'])
  .value('UserCard', UserCard)
  .directive('userCard', function(reactDirective) {
    return reactDirective('UserCard', ['user', 'onEdit']);
  });
```

**Verify**: Add `<user-card user="$ctrl.someUser"></user-card>` to any AngularJS template. The React component should render within the AngularJS page.

### 3. Establish shared state management with Redux

Set up a Redux store that both AngularJS and React components can access. This prevents state divergence during the migration period. [src4, src5]

```javascript
// store.js — Shared Redux store
import { configureStore, createSlice } from '@reduxjs/toolkit';

const userSlice = createSlice({
  name: 'users',
  initialState: { list: [], loading: false },
  reducers: {
    setUsers: (state, action) => { state.list = action.payload; },
    setLoading: (state, action) => { state.loading = action.payload; }
  }
});

export const { setUsers, setLoading } = userSlice.actions;
export const store = configureStore({ reducer: { users: userSlice.reducer } });
```

```javascript
// Connect AngularJS to the shared Redux store using ng-redux
import ngRedux from 'ng-redux';
import { store } from './store';

angular.module('myApp', [ngRedux])
  .config(($ngReduxProvider) => {
    $ngReduxProvider.provideStore(store);
  });

// In an AngularJS controller — subscribe to Redux state
function UserListCtrl($ngRedux, $scope) {
  const unsubscribe = $ngRedux.connect(
    (state) => ({ users: state.users.list }),  // mapState
    { setUsers }                                // mapDispatch
  )($scope);
  $scope.$on('$destroy', unsubscribe);
}
```

```jsx
// In a React component — read from the same Redux store
import { useSelector, useDispatch } from 'react-redux';
import { setUsers } from './store';

function UserList() {
  const users = useSelector(state => state.users.list);
  const dispatch = useDispatch();
  // Both AngularJS and React see the same state
  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
```

**Verify**: Dispatch an action from an AngularJS controller and confirm the React component re-renders with updated data, and vice versa.

### 4. Convert leaf components bottom-up

Start with the simplest, most isolated components at the bottom of your component tree and work upward. This minimizes risk and lets you build confidence. [src2, src4]

```jsx
// BEFORE: AngularJS directive
angular.module('myApp').directive('statusBadge', function() {
  return {
    restrict: 'E',
    scope: { status: '=' },
    template: '<span class="badge badge-{{status}}">{{status}}</span>'
  };
});

// AFTER: React component
function StatusBadge({ status }) {
  return <span className={`badge badge-${status}`}>{status}</span>;
}

// Register as Angular directive via bridge
angular.module('myApp')
  .component('statusBadge', react2angular(StatusBadge, ['status']));
```

Conversion priority order:
1. Pure display components (badges, icons, formatted text)
2. Form inputs and small interactive widgets
3. List items and card components
4. Container components with data fetching
5. Page-level components
6. Router (last)

**Verify**: Run your existing test suite after each component conversion. Both AngularJS and converted React components should behave identically.

### 5. Migrate routing last

Once the majority of your components are React, replace the AngularJS router with React Router. This is the most disruptive step and should be done last. [src4, src5]

```jsx
// Install React Router
// npm install react-router-dom

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { Dashboard } from './pages/Dashboard';
import { UserProfile } from './pages/UserProfile';
import { Settings } from './pages/Settings';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Dashboard />} />
        <Route path="/users/:id" element={<UserProfile />} />
        <Route path="/settings" element={<Settings />} />
      </Routes>
    </BrowserRouter>
  );
}
```

For a gradual router migration, use `@uirouter/react-hybrid` if your app uses UI-Router:

```bash
npm install @uirouter/react @uirouter/react-hybrid
```

**Verify**: Navigate to every route in your application and verify all pages render correctly. Check that browser back/forward navigation works. Confirm deep links resolve properly.

### 6. Remove AngularJS entirely

Once all components and routing are in React, remove the AngularJS dependency and all bridge code. [src2, src5]

```bash
# Remove AngularJS and bridge dependencies
npm uninstall angular angular-route angular-resource ngreact react2angular ng-redux
```

```jsx
// New entry point: index.jsx
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store';
import App from './App';

const root = createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);
```

**Verify**: `npm ls angular` returns empty (no AngularJS in dependency tree). Run full test suite. Bundle size should be significantly smaller.

## Code Examples

### JavaScript: Wrapping a React Component for AngularJS with react2angular

> Full script: [javascript-wrapping-a-react-component-for-angularj.js](scripts/javascript-wrapping-a-react-component-for-angularj.js) (46 lines)

```javascript
// Input:  A React component + AngularJS module
// Output: The React component available as an AngularJS directive
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { react2angular } from 'react2angular';
# ... (see full script)
```

### TypeScript: Full Migration of an AngularJS Service to a React Custom Hook

> Full script: [typescript-full-migration-of-an-angularjs-service-.ts](scripts/typescript-full-migration-of-an-angularjs-service-.ts) (81 lines)

```typescript
// Input:  AngularJS service with $http calls and state
// Output: React custom hook with equivalent functionality
// BEFORE: AngularJS service
// angular.module('myApp').factory('UserService', function($http) {
//   return {
# ... (see full script)
```

### JavaScript: Shared Redux Store Bridge Between AngularJS and React

> Full script: [javascript-shared-redux-store-bridge-between-angul.js](scripts/javascript-shared-redux-store-bridge-between-angul.js) (50 lines)

```javascript
// Input:  Redux store accessed by both AngularJS controllers and React components
// Output: Synchronized state across both frameworks during migration
import { configureStore, createSlice } from '@reduxjs/toolkit';
// 1. Define Redux slice (shared by both frameworks)
const filtersSlice = createSlice({
# ... (see full script)
```

## Anti-Patterns

### Wrong: Big-bang rewrite of the entire application

```javascript
// BAD — Stopping all feature development for months to rewrite everything
// This approach has a high failure rate and massive business risk [src2, src5]

// "Let's just rewrite the whole thing in React over the next 6 months"
// Meanwhile: no new features, no bug fixes, team morale drops,
// stakeholders lose patience, project gets cancelled
```

### Correct: Incremental migration with continuous delivery

```javascript
// GOOD — Migrate one component at a time while shipping features [src2, src4]
// Week 1: Set up React + bridge library
// Week 2: Convert 3 leaf components (badges, icons, tooltips)
// Week 3: Ship a new feature — write it in React from the start
// Week 4: Convert 2 more existing components
// ...continue until AngularJS is fully removed

// The app works at every step. Features keep shipping.
```

### Wrong: Duplicating state between AngularJS and React

```javascript
// BAD — Each framework maintains its own copy of the same data
// This causes state divergence bugs that are extremely hard to debug

// AngularJS controller
$scope.users = UserService.getAll(); // AngularJS has its own copy

// React component
function UserList() {
  const [users, setUsers] = useState([]); // React has its own copy
  useEffect(() => { fetch('/api/users').then(r => r.json()).then(setUsers); }, []);
  // BUG: AngularJS and React show different data after updates
}
```

### Correct: Single source of truth via shared Redux store

```javascript
// GOOD — One Redux store is the single source of truth [src4, src5]
// Both frameworks read from and write to the same store

import { store, setUsers } from './store';

// AngularJS reads from Redux via ng-redux
const unsubscribe = $ngRedux.connect(state => ({ users: state.users.list }))($scope);

// React reads from Redux via react-redux
function UserList() {
  const users = useSelector(state => state.users.list);
  // Both always show the same data
}
```

### Wrong: Converting the router first

```javascript
// BAD — Replacing the router breaks every route in the app at once [src4]
// This forces you to convert ALL page components simultaneously

// "Let's start by switching to React Router..."
// Result: Every page breaks. You now must convert everything before anything works.
```

### Correct: Convert the router last

```javascript
// GOOD — Convert leaf components and pages first, router last [src4, src5]
// 1. Convert UI components (buttons, cards, forms)
// 2. Convert page-level components (each page becomes a React component)
// 3. Only THEN replace the AngularJS router with React Router
// At step 3, all pages are already React — the router swap is straightforward
```

### Wrong: Direct DOM manipulation in React components

```javascript
// BAD — Using jQuery or direct DOM manipulation inside React components
// React manages its own virtual DOM; direct manipulation causes conflicts [src1]

function BadComponent() {
  useEffect(() => {
    // DO NOT DO THIS — React and jQuery will fight over the DOM
    $('#my-element').addClass('active');
    document.querySelector('.sidebar').innerHTML = '<p>Updated</p>';
  }, []);
  return <div id="my-element">Content</div>;
}
```

### Correct: Let React manage its own DOM, isolate legacy DOM access

```javascript
// GOOD — Use React state and refs; isolate non-React DOM to dedicated containers [src1]
function GoodComponent({ isActive }) {
  return (
    <div className={isActive ? 'active' : ''}>
      Content managed by React
    </div>
  );
}

// For legacy jQuery plugins that MUST touch the DOM, isolate them:
function LegacyPluginWrapper() {
  const containerRef = useRef(null);
  useEffect(() => {
    // Safe: React won't touch this empty div's children
    $(containerRef.current).datepicker({ format: 'yyyy-mm-dd' });
    return () => $(containerRef.current).datepicker('destroy');
  }, []);
  return <div ref={containerRef}></div>; // React renders empty div, jQuery fills it
}
```

## Common Pitfalls

- **Prop name casing mismatch**: AngularJS templates use kebab-case (`on-search`), but React uses camelCase (`onSearch`). When using `react2angular`, the attribute-to-prop mapping handles this automatically, but if you use `ngReact`'s `reactDirective`, you must explicitly list prop names in camelCase in the second argument. Fix: Always declare the camelCase prop names array: `reactDirective('MyComponent', ['onSearch', 'userName'])`. [src4, src6]
- **Digest cycle not triggered after React state change**: When React updates state that AngularJS depends on (via callbacks or shared services), AngularJS may not detect the change because it happens outside the digest cycle. Fix: Wrap callbacks with `$scope.$apply()` or use `$ngRedux` which handles digest integration automatically. [src4]
- **Memory leaks from unsubscribed Redux connections**: Forgetting to unsubscribe `$ngRedux.connect()` in AngularJS controllers when the scope is destroyed leads to memory leaks and ghost updates. Fix: Always call the returned unsubscribe function in `$scope.$on('$destroy', unsubscribe)`. [src4]
- **Bundle size bloat during migration**: Running both AngularJS and React simultaneously roughly doubles your JavaScript bundle size. Fix: Use code-splitting (`React.lazy` + dynamic `import()`) to load React components on demand, and tree-shake unused AngularJS modules as you migrate them. [src2, src5]
- **Test suite breaks from mixed rendering**: Existing Karma/Jasmine tests for AngularJS components may fail when the component is converted to React. Fix: Migrate tests alongside components — use Jest + React Testing Library for converted components, keep Karma for remaining AngularJS components. Run both test suites in CI until migration is complete. [src5]
- **$http interceptors lost when switching to fetch/axios**: AngularJS `$http` interceptors (for auth tokens, error handling, loading spinners) have no automatic equivalent in React. Fix: Create an Axios instance with interceptors or a `fetch` wrapper that replicates the same behavior: auth header injection, 401 redirect, global error handling. [src3, src5]
- **CSS/style conflicts between frameworks**: AngularJS directives often rely on `ng-scope`, `ng-isolate-scope`, and other Angular-specific CSS classes that React components don't generate. Fix: Use CSS modules or a CSS-in-JS library (styled-components, Emotion) for React components to scope styles and avoid conflicts with AngularJS global styles. [src2]
- **Mutation Events removal breaks AngularJS**: Chrome 127+ removed Mutation Events that AngularJS relies on for DOM observation. Fix: Apply HeroDevs NES patch or polyfill `MutationEvent` with `MutationObserver` wrapper before migrating. [src8, src10]
- **Synchronous XHR removed in Chrome 130+ / Safari 19**: AngularJS bootstrap performs synchronous XMLHttpRequest for uncached template fetches, which now throws in modern Chrome and Safari. Symptoms: blank page or "NetworkError: synchronous XHR on the main thread is deprecated" during app initialization. Fix: pre-bundle all templates via `ng-html2js` Karma preprocessor or `$templateCache.put()` so bootstrap never issues runtime XHRs. HeroDevs NES backports an async loader. [src8, src10]

## Diagnostic Commands

> Full script: [diagnostic-commands.sh](scripts/diagnostic-commands.sh) (25 lines)

```bash
# Check AngularJS version in your project
npm ls angular | head -5
# Expected: angular@1.x.x (1.5+ required for react2angular)

# Check if react2angular is installed
npm ls react2angular
# Expected: react2angular@4.x.x

# Count remaining AngularJS module declarations (migration progress)
grep -r "angular\.module\(" src/ --include="*.js" --include="*.ts" | wc -l

# Count remaining AngularJS directives
grep -r "\.directive\(" src/ --include="*.js" --include="*.ts" | wc -l

# Count remaining AngularJS controllers
grep -r "\.controller\(" src/ --include="*.js" --include="*.ts" | wc -l

# Count remaining $scope usage (unconverted code indicator)
grep -r "\$scope" src/ --include="*.js" --include="*.ts" | wc -l

# Analyze bundle size to track bloat during migration
npx webpack-bundle-analyzer dist/stats.json

# Run both test suites during migration period
npx karma start karma.conf.js && npx jest --coverage

# Check for known AngularJS CVEs in your dependency tree
npm audit | grep -i angular
```

## Version History & Compatibility

| Technology | Version | Status | Migration Notes |
|---|---|---|---|
| AngularJS 1.8.x | Final release (1.8.3) | EOL since Dec 2021 | 8+ unpatched CVEs; HeroDevs offers commercial NES [src7, src8] |
| AngularJS 1.5-1.7 | Older | EOL | Component API available from 1.5+; required for react2angular [src6] |
| AngularJS 1.2-1.4 | Legacy | EOL | No component API; must use ngReact with directive bridge |
| react2angular 4.x | Bridge library | Maintained | Supports React 16-17; for React 18 use `react18-react2angular` fork |
| ngReact | Bridge library | Archived | No longer maintained; use react2angular if possible [src4] |
| angular2react | Reverse bridge | Maintained | Wraps AngularJS components for use in React; useful during late migration |
| React 18.x | Current | Active | Concurrent features; use react18-react2angular for bridge |
| React 19.x | Latest | Active | Stable since Dec 2024; test bridge compatibility before upgrading |

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| AngularJS 1.x app needs modernization (EOL framework) | App is already on Angular 2+ (modern Angular) | Upgrade within Angular ecosystem or consider Angular-to-React migration |
| Team knows React or wants to adopt it | Team prefers Vue.js or Svelte | Migrate AngularJS to Vue (vue-in-angularjs) or Svelte |
| App is under active development with new features | App is being decommissioned within 6 months | Keep AngularJS; apply security patches only via HeroDevs NES |
| Codebase is > 10K LOC and rewrite is too risky | App is < 5K LOC with simple UI | Clean rewrite may be faster than incremental migration |
| You need the React ecosystem (React Native, Next.js, etc.) | You only need better TypeScript support | Consider migrating to Angular 17+ which has excellent TS support |
| PCI DSS 4.0 or FedRAMP compliance is required | App is internal-only with no compliance requirements | HeroDevs NES as interim solution while planning migration [src8] |

## Important Caveats

- AngularJS reached end-of-life on December 31, 2021. It still had approximately 419,000 weekly npm downloads as of early 2025, but no security patches are released for the open-source version. Ten or more CVEs have been disclosed since EOL, including CVE-2024-21490 (ng-srcset ReDoS), CVE-2024-8372/8373 (image sanitization), CVE-2025-4690 and CVE-2025-2336 (ng-sanitize linky filter DoS/bypass), and CVE-2026-22610 (Template Compiler XSS via unsanitized SVG `href`/`xlink:href` script attributes). Migrating is a security and compliance imperative, not just a technical preference. [src7, src8, src9]
- PCI DSS 4.0 explicitly bans EOL frameworks without verified mitigation strategies (Requirement 6.3.2 — inventory of custom software with known-vulnerability tracking). FedRAMP/Executive Order 14028 SBOM requirements flag unsupported components as major NIST SP 800-53 CM-8 deficiencies that can trigger Authorization to Operate (ATO) denial. Organizations in regulated industries must prioritize migration or adopt HeroDevs NES (FedRAMP, HIPAA, PCI DSS, SOC 2, ISO 27001 compatible) as an interim measure. [src8, src10]
- Chrome 127+ removed Mutation Events, Chrome 130+ blocks synchronous XHR on the main thread, and Safari 19 continues removing legacy APIs that AngularJS depends on. Symptoms are silent — directives fail to detect dynamically injected DOM, or bootstrap hangs on the first template fetch — so production breakage often appears only when end-user browsers auto-update. Apply HeroDevs NES patches or polyfills before each major Chrome/Safari release. [src8, src9, src10]
- The `react2angular` bridge library adds overhead: each bridged component creates an AngularJS directive wrapper that handles prop passing and lifecycle synchronization. For performance-critical paths with hundreds of bridged components, consider batching conversions to reduce bridge overhead.
- During the migration period (which can last 6-18 months for large codebases), you will ship a larger JavaScript bundle since both AngularJS and React are included. Plan for this impact on load times and consider aggressive code-splitting. [src2, src5]
- AngularJS's dependency injection system (`$inject`) has no direct React equivalent. Services that use DI must be refactored to use ES module imports, React Context, or a dependency injection library like `inversify`. Plan this refactoring as part of each component conversion.
- Two-way data binding (`ng-model`) is fundamentally different from React's one-way data flow. Components that rely heavily on two-way binding require more effort to convert because you must explicitly implement the `onChange` callback pattern. [src1]
- If your AngularJS app uses `$compile` for dynamic template rendering, you'll need to replace this with React's `dangerouslySetInnerHTML` (for static HTML) or dynamic component rendering patterns. This is one of the hardest patterns to migrate.

## Related Units

- [AngularJS to Angular Migration Guide](/software/migrations/angularjs-to-angular/2026)
- [Angular to React Migration Guide](/software/migrations/angular-to-react/2026)
- [jQuery to React Migration Guide](/software/migrations/jquery-to-react/2026)
- [JavaScript to TypeScript Migration Guide](/software/migrations/javascript-to-typescript/2026)
