This error occurs when React is not properly imported or in scope when JSX is used. It commonly happens due to missing import statements, incorrect bundler configuration, or issues with the React 17+ JSX transform.
The "ReferenceError: React is not defined" error occurs when your JavaScript code tries to use JSX syntax but the React library is not available in the current scope. This is a fundamental requirement because JSX is not native JavaScript - it needs to be transformed into React.createElement() calls (in React 16 and earlier) or jsx-runtime functions (in React 17+). Prior to React 17, every file containing JSX required an explicit `import React from 'react'` statement at the top, even if React wasn't directly referenced in your code. The JSX transformer relied on React being in scope to compile JSX elements. With React 17's new JSX transform, this requirement was removed when using the automatic runtime configuration, but many projects still encounter this error due to misconfiguration or outdated build setups. This error typically manifests during the build process or at runtime when the bundler (Webpack, Vite, etc.) or transpiler (Babel, TypeScript) cannot resolve the React reference needed for JSX compilation.
Check that React is listed in your package.json dependencies:
npm list react
# or
yarn list reactIf React is not installed or shows errors, install it:
npm install react react-dom
# or
yarn add react react-domEnsure you're installing compatible versions of React and ReactDOM.
For React 16 and earlier, or React 17+ without automatic JSX runtime, add this import to the top of every file using JSX:
import React from 'react';
function MyComponent() {
return <div>Hello World</div>;
}
export default MyComponent;This ensures React is in scope when JSX is transformed to React.createElement() calls.
If you're using React 17 or later, enable the automatic JSX runtime to eliminate the need for React imports. Update your Babel configuration:
For .babelrc or babel.config.js:
{
"presets": [
"@babel/preset-env",
["@babel/preset-react", {
"runtime": "automatic"
}]
]
}For Next.js: This is enabled by default in Next.js 11+.
For Create React App: Automatic since CRA 4.0.0 with React 17+.
For TypeScript (tsconfig.json):
{
"compilerOptions": {
"jsx": "react-jsx"
}
}After this configuration, you no longer need to import React for JSX to work.
Ensure your build tools are properly configured to handle React:
Check Babel presets include React:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}For Webpack, ensure babel-loader is configured for .jsx and .js files:
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react']
}
}
}
]
},
resolve: {
extensions: ['.js', '.jsx']
}
};Install required packages if missing:
npm install --save-dev @babel/core @babel/preset-react babel-loaderIf you're loading React via CDN or script tags, ensure React is loaded before your component code:
<!DOCTYPE html>
<html>
<head>
<!-- Load React first -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
</head>
<body>
<div id="root"></div>
<!-- Load your component code after React -->
<script src="./your-app.js"></script>
</body>
</html>The order is critical - React must be available before any code that uses it.
Build tool caches can sometimes cause issues after configuration changes:
# For npm
rm -rf node_modules/.cache
npm run build
# For Webpack
rm -rf node_modules/.cache
npx webpack --mode development
# For Next.js
rm -rf .next
npm run dev
# For Create React App
rm -rf node_modules/.cache
npm startAlso try deleting and reinstalling node_modules if the issue persists:
rm -rf node_modules package-lock.json
npm installMigration from React 16 to React 17+:
When upgrading from React 16 to React 17 or later, you have two options:
1. Keep existing imports (backward compatible) - React 17+ still supports the old pattern
2. Enable automatic runtime and remove React imports from JSX files
The automatic runtime has several benefits:
- Smaller bundle size (React isn't imported unnecessarily)
- Better developer experience (less boilerplate)
- Forward compatibility with future React features
TypeScript JSX Configuration Options:
The jsx compiler option in tsconfig.json has several values:
- "react": Classic transform, requires React in scope (React 16 style)
- "react-jsx": New transform, automatic runtime (React 17+)
- "react-jsxdev": Development version of react-jsx with better debugging
- "preserve": Keeps JSX unchanged for another tool to process
- "react-native": Keeps JSX for React Native bundler
Framework-Specific Notes:
- Gatsby: Requires gatsby-plugin-react-helmet and proper Babel configuration. Some Gatsby versions had issues with React 17's JSX transform.
- Meteor: When upgrading to React 17+, you may need to update your Babel configuration in .babelrc or package.json
- Rails with react-rails gem: Ensure both the gem and npm packages are compatible versions
Monorepo Considerations:
In monorepo setups (Lerna, Nx, Turborepo), ensure React is installed at the correct level (workspace root vs individual packages) and that Babel configurations are properly inherited or overridden.
Prop spreading could cause security issues
Prop spreading could cause security issues
Error: error:0308010C:digital envelope routines::unsupported
Error: error:0308010C:digital envelope routines::unsupported
React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.
React Hook useEffect placed inside a condition
Hook can only be called inside the body of a function component
Hook can only be called inside the body of a function component
Rollup failed to resolve import during build
How to fix "Rollup failed to resolve import" in React