iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Antihost offers managed WordPress hosting with free migration, one-click staging and a 14-day free trial.
The most reliable way to embed an existing React application in WordPress is to treat React as a controlled “island” inside a WordPress-rendered page: build the app for production, output a mount element such as <div id="my-react-app"></div>, and enqueue the generated JavaScript and CSS through WordPress. Use wp_enqueue_script() on the wp_enqueue_scripts hook, load files only where the mount exists, and let React call the WordPress REST API for content or authenticated operations.
This approach preserves WordPress templates, menus, editor workflows and search-engine-facing HTML while giving one section of the page React’s component model. A headless React frontend or an iframe can be appropriate in different circumstances, but each changes who owns routing, hosting, styling, security and SEO.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Choose the integration boundary first
Decide which system owns the document before moving files. The choice determines deployment, authentication, previews, accessibility and how much WordPress remains involved in rendering.
| Architecture | Best when | Main trade-off | What each system owns |
|---|---|---|---|
| React island in a theme or plugin | WordPress should continue to render the page, navigation, SEO templates and editor-controlled content. | The bundle must be loaded correctly inside an existing theme, and its CSS and JavaScript must avoid conflicts. | WordPress owns the document and routing; React owns the selected interactive region; the REST API is the data boundary. |
| Headless or separately hosted React frontend | React should own nearly all routing and UI, with WordPress used primarily as a content backend. | You add hosting, deployment coordination, preview handling, authentication and usually a CORS policy. | React owns pages and navigation; WordPress owns content and API responses. |
| Iframe or external embed | The application is maintained as a completely separate product and visual inclusion is the only requirement. | WordPress navigation, styling, accessibility, analytics and shared state do not naturally cross the iframe boundary. | The external application owns its document; WordPress supplies only the containing frame. |
For most existing sites, start with a React island. Choose headless only when the frontend genuinely needs independent routing and deployment. Use an iframe for deliberate isolation, not as a shortcut for an app that needs tight integration with WordPress.
#1 Best Overall
Prerequisites and project decisions
- A working WordPress installation where you can add a small custom plugin or edit a child theme.
- A production build of the React project and a clear list of the files it emits.
- A unique mount ID and a decision about which pages should display it.
- A data plan: public REST endpoints, a custom endpoint, or authenticated requests for private operations.
- A strategy for cache invalidation, usually a version derived from the asset file’s modification time or the build version.
- Access to browser developer tools and a staging site where the active theme’s CSS and caching layers can be tested.
Put site-specific integration code in a plugin when the app should survive a theme change. A child theme is reasonable when the application is inseparable from one theme’s templates and styling. Keep the compiled React files inside that same controlled directory or on an asset host whose URL and cache policy you control.
Build the React application for production
Run the build command defined by the project rather than loading a development server in WordPress. A development server is designed for local hot reloading, not stable URLs, caching or production error handling.
- Run the project’s documented production build command.
- Inspect the output directory and record every JavaScript and CSS file that the build requires. Some bundlers emit hashed filenames and separate chunks.
- Copy the complete output, including any dynamically imported chunks and public assets, into the plugin or theme directory. Do not copy only the first JavaScript file if the generated runtime references additional files.
- Confirm that the bundler’s base or public path points to the directory from which WordPress will serve those files. An incorrect base path commonly produces a blank app with 404 errors for chunks.
- Open the built entry file and verify that it does not assume the app is hosted at the domain root when it will actually live below a plugin or theme URL.
Keep source code and build output conceptually separate. WordPress needs the compiled assets; it does not need your development dependencies or source maps exposed publicly unless you have an explicit debugging policy.
Render a mount element from WordPress
React needs a stable element in the server-rendered HTML. A shortcode is convenient when editors should place the app on selected pages; a block render callback gives block-editor controls; a page template is suitable when the app belongs to one route.
Shortcode example
<?php
function my_react_app_shortcode( $atts = array(), $content = null ) {
return '<div id="my-react-app" class="my-react-app-root"></div>';
}
add_shortcode( 'my_react_app', 'my_react_app_shortcode' );
An editor can then insert [my_react_app] in the intended page. Keep the shortcode output deterministic: the JavaScript should be able to find exactly one root element, and the class should provide a scope for app styles.
Template or block output
In a page template, place the same element where the application should appear. For a dynamic block, return the mount element from the block’s server-side render callback. Whichever method you use, enqueue assets conditionally using the same condition that identifies the rendered page; do not make the browser download the application on every WordPress route.
Free tools Windows power users keep installed
One-click scans. No signup required.
Enqueue JavaScript and CSS through WordPress
wp_enqueue_script() is WordPress’s recommended mechanism for adding JavaScript. It registers or enqueues a handle, source URL, dependencies, version and loading arguments so WordPress can generate the correct tag and account for dependency order.
Plugin-based front-end integration
<?php
function my_react_app_enqueue_assets() {
if ( ! is_page( 'interactive-tools' ) ) {
return;
}
$plugin_url = plugin_dir_url( __FILE__ );
$plugin_path = plugin_dir_path( __FILE__ );
$script_path = $plugin_path . 'build/assets/app.js';
$style_path = $plugin_path . 'build/assets/app.css';
wp_enqueue_script(
'my-react-app',
$plugin_url . 'build/assets/app.js',
array(),
file_exists( $script_path ) ? filemtime( $script_path ) : '1.0.0',
array( 'strategy' => 'defer', 'in_footer' => true )
);
if ( file_exists( $style_path ) ) {
wp_enqueue_style(
'my-react-app',
$plugin_url . 'build/assets/app.css',
array(),
filemtime( $style_path )
);
}
}
add_action( 'wp_enqueue_scripts', 'my_react_app_enqueue_assets' );
Replace the page condition with the one that matches your mount logic. If a shortcode can appear on several pages, set a flag when the shortcode runs and enqueue assets later only when that flag is true. A file modification time is a practical cache-busting version; a release number works when your deployment process updates it reliably.
Theme-based paths
Inside a theme, use the theme URL helper rather than a hardcoded domain. The principle is the same: provide a unique handle, the correct file URL, dependencies, a version and an appropriate loading strategy. Never assume the site is installed at /; WordPress may run in a subdirectory or behind a reverse proxy.
Dependencies and deferred loading
If the bundle expects another registered script, list that handle in the dependency array. WordPress can apply a strategy such as defer, but it considers dependency order when deciding whether a strategy is safe. Do not mark a script deferred merely to improve a score if another script must execute first and the dependency is not declared.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteRank #3
Admin screens
For a React interface in the dashboard, use the admin_enqueue_scripts hook and check the current screen before loading the bundle:
<?php
function my_react_admin_assets( $hook_suffix ) {
if ( 'toplevel_page_my-react-app' !== $hook_suffix ) {
return;
}
wp_enqueue_script(
'my-react-admin',
plugins_url( 'build/admin.js', __FILE__ ),
array(),
'1.0.0',
array( 'strategy' => 'defer', 'in_footer' => true )
);
}
add_action( 'admin_enqueue_scripts', 'my_react_admin_assets' );
Keep front-end and admin handles distinct. An admin bundle may use capabilities, nonces and endpoints that should never be exposed to anonymous visitors.
Start React only when the mount exists
The entry point should fail safely if a template is cached without the mount or if another page accidentally receives the script.
import { createRoot } from 'react-dom/client';
import App from './App';
import './styles.css';
const mount = document.getElementById('my-react-app');
if (mount) {
createRoot(mount).render(<App />);
}
Use a unique ID if only one instance is expected. If editors may place multiple instances on one page, render a class-based selector and pass per-instance configuration through data attributes or a JSON script element; then create one React root for each element.
Connect React to WordPress data
The WordPress REST API is JSON-based, uses predictable resource-oriented URLs and HTTP methods, and supports endpoint discovery. Public posts, pages and taxonomies can be requested from the standard /wp-json/wp/v2/ namespace. App-specific behavior belongs in a custom namespace rather than in ad hoc query strings attached to unrelated endpoints.
Rank #4
Reading public content
import { useEffect, useState } from 'react';
export default function Posts() {
const [posts, setPosts] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/wp-json/wp/v2/posts?per_page=10')
.then((response) => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then(setPosts)
.catch(setError);
}, []);
if (error) return <p role="alert">Unable to load posts.</p>;
return <ul>{posts.map((post) => <li key={post.id}>{post.title.rendered}</li>)}</ul>;
}
For a site installed in a subdirectory, do not hardcode the domain or assume a root-relative path is correct. Pass the REST URL from PHP to JavaScript using a localized value or a JSON configuration object generated from WordPress’s URL functions.
Creating a custom route
Register a namespaced route in PHP and give it a permission callback. Return only the fields the application needs; reducing the response makes the contract easier to secure and maintain.
<?php
add_action( 'rest_api_init', function () {
register_rest_route( 'my-app/v1', '/profile', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'my_app_profile',
'permission_callback' => function () {
return is_user_logged_in();
},
) );
} );
function my_app_profile( WP_REST_Request $request ) {
$user = wp_get_current_user();
return array(
'id' => $user->ID,
'name' => $user->display_name,
'email' => $user->user_email,
);
}
The permission callback is not optional for a private route. Authentication and authorization must be enforced on the server for every write or private read; hiding a button in React is not a security control.
Authenticated writes and nonces
For a logged-in browser request, pass a WordPress REST nonce and send it in the X-WP-Nonce header. Generate the nonce in PHP and expose it to the app through a narrowly scoped configuration object. On the server, check the nonce, verify the current user’s capability, validate every field and reject unexpected values. Use HTTPS and do not put passwords, long-lived secrets or privileged API keys in the bundle.
fetch(window.myAppSettings.restUrl + 'my-app/v1/item', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': window.myAppSettings.nonce
},
body: JSON.stringify({ title: 'Example' })
});
Nonce checks help prevent cross-site request forgery; they do not replace capability checks, input validation or output escaping. Treat everything arriving from the browser as untrusted.
Best Value
Using the WordPress JavaScript client
If your code uses the WordPress REST API JavaScript client, declare the documented wp-api dependency when registering the script. Otherwise, a direct fetch() call is sufficient and avoids adding a dependency your bundle does not use.
Keep CSS and markup from colliding with the theme
WordPress themes often define broad selectors for headings, buttons, lists and forms. Scope application styles beneath the root class:
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minute.my-react-app-root {
--app-accent: #2457d6;
isolation: isolate;
}
.my-react-app-root .button {
background: var(--app-accent);
border: 0;
}
.my-react-app-root h2 {
font-size: 1.5rem;
}
Avoid global resets such as * { box-sizing: border-box; } unless you intentionally control the entire page. Test focus outlines, form controls, contrast, reduced-motion preferences and keyboard navigation with the active theme. Keep the mount element in a semantic region, give interactive controls accessible names, and announce asynchronous errors with an appropriate live region.
When an iframe is the right boundary
An iframe can isolate incompatible dependencies, a separate release cycle or a product that must run unchanged on several host platforms. Set an explicit width and height strategy, provide a descriptive title, and plan for responsive behavior. The iframe will not automatically inherit WordPress fonts, colors, login state, analytics context or navigation. Cross-window communication requires a deliberate postMessage protocol with origin checks. If the app needs shared state, deep links, WordPress user permissions or seamless accessibility, an island or headless integration is usually a better fit.
Deployment, caching and environment handling
- Build the React project in the same environment used for release, or pin the build toolchain so output is reproducible.
- Copy every emitted asset and preserve the directory structure expected by the JavaScript runtime.
- Deploy the plugin or child-theme code and verify that the generated URLs return the correct content type rather than an HTML login page.
- Use a changed version string, such as the asset modification time, whenever a bundle changes. This prevents browsers and page caches from retaining an incompatible old file.
- Clear any full-page, object or CDN cache that captured HTML containing an old asset reference.
- Keep API base URLs and feature flags environment-specific. Generate them from WordPress configuration instead of hardcoding a staging hostname into the production bundle.
If your bundler emits content-hashed filenames, update the enqueue code or manifest lookup on every release. A stale reference to a deleted hash produces a blank mount even though the WordPress page itself loads normally.
SEO, previews and rendering expectations
A React island leaves the surrounding page, title, canonical tags and structured WordPress content server-rendered. That is useful when the interactive app is an enhancement rather than the page’s only content. Text that must be indexed or visible without JavaScript should remain in WordPress HTML or have a meaningful server-rendered fallback.
Recommended Free Tools
In a headless architecture, React owns metadata and routing, so you must implement canonical URLs, titles, descriptions, social cards, sitemap behavior, preview authentication and error pages in the frontend. WordPress editor previews also require coordination: a draft REST response may need authenticated access, while a public cached page should never expose draft data.
Troubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
| Blank area where the app should appear | The mount ID does not match, the bundle throws before mounting, or a required chunk returns 404. | Inspect the console and Network panel, confirm the exact element ID, and verify every emitted asset URL. |
| JavaScript file loads as HTML | A wrong path, rewrite rule or authentication layer is returning a WordPress page. | Open the asset URL directly and correct the plugin/theme URL or server rule until the response is JavaScript with a successful status. |
| App works locally but not in production | The bundler base path assumes the domain root, or the site runs in a subdirectory. | Configure the production public path and generate the REST URL from WordPress rather than from a hardcoded origin. |
| Old interface remains after deployment | Browser, page or CDN cache still references the previous bundle. | Change the enqueue version, purge relevant caches and confirm the HTML points to the new asset. |
| Requests return 401 or 403 | The route requires authentication, the nonce is missing or expired, or the user lacks the capability. | Check login state, send a fresh nonce, implement the correct permission callback and show a useful sign-in or authorization message. |
| REST request is blocked by the browser | A separately hosted frontend is calling WordPress without an appropriate CORS policy. | Configure a narrowly scoped allowed origin on the server, or serve the island from the same origin to avoid unnecessary cross-origin requests. |
| Theme styles change the app | Broad selectors or a reset affect React markup. | Scope selectors below the root class, increase specificity only where needed and test with the real active theme. |
| React appears twice | The script is enqueued more than once or two mounting paths target the same element. | Use one unique handle, remove duplicate enqueue calls and ensure only one root is created for each mount. |
Boundary test checklist
- Visit a page that should not contain the app and confirm the bundle is absent from its source and Network panel.
- Visit every page that should contain it with a logged-out browser and a logged-in browser.
- Test a fresh browser profile so cached development files cannot hide a bad production path.
- Disable JavaScript temporarily and verify that essential page content still has a usable fallback.
- Test keyboard-only navigation, focus order, visible focus, contrast and a narrow viewport.
- Exercise successful, validation-error, expired-nonce and insufficient-permission API responses.
- Confirm that private fields are not present in anonymous JSON responses or embedded configuration.
- Change the active theme on staging, if possible, to reveal unscoped CSS assumptions.
- Check browser console, server logs and REST responses after every deployment.
Practical decision guide
Use a React island when
- Editors need to place the app inside selected WordPress pages.
- WordPress should retain control of navigation, templates, metadata and most content.
- The app can operate within one mount element and use REST requests for dynamic data.
Use a headless frontend when
- React needs to own routing, page transitions and nearly the entire visitor experience.
- Your team can operate separate hosting, deployments, previews, authentication and caching.
- You are prepared to implement frontend SEO and cross-origin policies explicitly.
Use an iframe when
- Isolation is more important than shared styling, navigation, state and analytics.
- The external product cannot be modified to integrate with WordPress directly.
For the typical WordPress site that needs one interactive tool, dashboard or configurator, the island pattern is the smallest boundary that preserves WordPress strengths while allowing React to handle complex interaction. Build the app, render a controlled mount, enqueue assets on the correct hook, isolate CSS, and enforce all data permissions on the server.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

