Scaffolding the React Admin Dashboard for WordPress Plugins
Learn how to scaffold your React admin dashboard by registering a WordPress menu, creating a root container, and mounting your application into the DOM.
Previously in this course, we built a robust service layer in Building the Knowledge Base Service Layer to handle our API interactions. Now that our data fetching is ready, we need a place to display it. In this lesson, we are scaffolding the React admin dashboard, which involves three distinct phases: registering the WordPress admin menu, creating a React container component, and finally, mounting that component into the DOM.
The Bridge Between WordPress and React
WordPress is a server-side framework that renders HTML via PHP. React, however, is a client-side library that manages its own virtual DOM. To bring them together, we use a "Mounting Pattern."
We output an empty <div> with a unique ID from PHP. Then, we write a small JavaScript snippet that waits for the DOM to be ready, finds that <div>, and tells React to "take over" that specific node. This keeps WordPress in charge of the page structure while letting React handle the dynamic UI components.
1. Registering the Admin Menu
First, we need a persistent home for our dashboard. Open your main plugin file and register a new top-level menu page.
PHPadd_action( 'admin_menu', 'kb_register_admin_page' ); function kb_register_admin_page() { add_menu_page( 'Knowledge Base Dashboard', 'Knowledge Base', 'manage_options', 'knowledge-base', 'kb_render_admin_page', 'dashicons-book-alt' ); } function kb_render_admin_page() { #6A9955">// This div is the "root" where React will mount echo '<div id="kb-admin-app"></div>'; }
2. Creating the React Container Component
In your src/ directory, create a folder named components and a file inside called App.js. This will serve as the root of your application.
JSXimport React from CE9178">'react'; const App = () => { return ( <div className="kb-container"> <h1>Knowledge Base Dashboard</h1> <p>React is successfully mounted!</p> </div> ); }; export default App;
3. Rendering React into the DOM
Now, we need to wire these two pieces together. Create an index.js file in your src/ directory. This is the entry point that your build process (configured in Introduction to @wordpress/scripts) will compile into a standalone file.
JAVASCRIPTimport React from CE9178">'react'; import { createRoot } from CE9178">'react-dom/client'; import App from CE9178">'./components/App'; const container = document.getElementById(CE9178">'kb-admin-app'); if (container) { const root = createRoot(container); root.render(<App />); }
The Build Process
After creating these files, remember to run npm run build in your terminal. This command processes your JSX and creates the compiled JavaScript file in your build/ folder. Ensure you are enqueuing this file in your plugin using wp_enqueue_script, making sure to list wp-element as a dependency so that React is available in the browser.
Hands-on Exercise
- Update your PHP: Ensure you have added the
wp_enqueue_scriptcall to youradmin_menuhook, pointing to your compiledbuild/index.js. - Verify Mounting: Check your browser console. If you see the content of your
App.jsrendered on the admin page, you have successfully scaffolded your dashboard. - Challenge: Add a simple state variable in
App.jsusinguseStatethat toggles a "Loading..." message when the component mounts.
Common Pitfalls
- Missing
wp-elementdependency: If you forget to addwp-elementto your script dependencies, React will be undefined, and your code will throw a silent error. Always check the network tab to see ifreactandreact-domare loading. - Duplicate IDs: Ensure the ID used in
document.getElementByIdmatches exactly what you echoed in your PHP function. - Script Execution Timing: If you try to render before the DOM is ready, your app will fail. Using the
deferattribute or enqueuing your script in the footer ($in_footer = true) is best practice. - Layout Shifts: As discussed in React rendering and layout shifts: A guide to stable UIs, rendering dynamic content into the DOM can cause jumps if the container doesn't have a defined minimum height. Consider setting a min-height on your
#kb-admin-appdiv.
Recap
We've moved from static PHP pages to a dynamic React-powered dashboard. By registering a dedicated menu, creating a root component, and mounting it into a specific DOM node, we've created the architecture needed for a modern WordPress plugin. This setup is the foundation for all the interactive features we'll build in the following lessons.
Up next: We will begin populating this dashboard with actual UI elements by working with @wordpress/components.
Work with me

Custom WordPress Plugin Development
Custom WordPress & WooCommerce plugins built to standard โ by the developer behind a plugin with 5,000+ active installs and a SaaS with 10,000+ users.

Headless WordPress + Next.js Frontend Development
Keep WordPress for content, get a lightning-fast Next.js frontend. The best of both worlds โ familiar editing, modern speed.