Learn to build interactive React forms in WordPress using controlled components. Master state management and submission events for your admin dashboard.
Previously in this course, we covered working with @wordpress/components to build the visual shell of our admin dashboard. Now that we have the layout, it's time to make it functional. In this lesson, we are building the "Add Entry" form, which is the heart of our plugin's data entry interface.
To build effective user interfaces, we must master the concept of Forms and Controlled components. In React, a controlled component is a form element whose value is driven entirely by state, making the data flow predictable and easy to debug.
In vanilla HTML, form elements like <input> or <textarea> maintain their own internal state (the text currently typed into the box). In React, we shift that responsibility to the component's state.
When you use a controlled component, the input's value attribute is tied to a variable in your useState hook. Every time the user types, an onChange event fires, and we update that state variable. React then re-renders the component with the new value. This cycle—State → UI → Event → State—is the foundation of modern React development.
Let’s implement a form to capture a title and description for our Knowledge Base. We will use the useState hook to track the input values and a handler function to manage form submission.
JSXimport { useState } from CE9178">'@wordpress/element'; import { Button, TextControl, TextareaControl } from CE9178">'@wordpress/components'; const KnowledgeBaseForm = () => { // Initialize state for form fields const [title, setTitle] = useState(CE9178">''); const [content, setContent] = useState(CE9178">''); const handleSubmit = (event) => { // Prevent the browser from performing a standard page reload event.preventDefault(); console.log(CE9178">'Submitting:', { title, content }); // Reset the form after submission setTitle(CE9178">''); setContent(CE9178">''); }; return ( <form onSubmit={handleSubmit}> <TextControl label="Entry Title" value={title} onChange={(value) => setTitle(value)} /> <TextareaControl label="Entry Content" value={content} onChange={(value) => setContent(value)} /> <Button isPrimary type="submit"> Add Entry </Button> </form> ); }; export default KnowledgeBaseForm;
useState('') to initialize our fields as empty strings.value prop of the TextControl is explicitly set to our state variable (title). If you remove the onChange handler, the input would become read-only because the state never updates to reflect the user's typing.handleSubmit function includes event.preventDefault(). This is critical; without it, the browser will attempt a traditional GET/POST request, triggering a page refresh that destroys your React application's state.Now it's your turn to extend the form.
TextControl to the form above specifically for a "Category" field.category using useState.handleSubmit function to include the category in the console.log output.When building Forms with Controlled components, developers often trip over these three issues:
event.preventDefault(): As mentioned, this is the #1 cause of "why does my page reload when I submit?". Always include it as the first line in your submit handler.onChange handlers: If you define a value prop on an input but omit the onChange handler, the input will appear "stuck" and the user won't be able to type anything.useState calls are fine. However, if your form grows to 10+ fields, consider using a single state object with useState({ title: '', content: '', category: '' }) and a single change handler that updates the object using the spread operator: setFormData({ ...formData, [name]: value }).By mastering these patterns, you ensure that your plugin's data layer remains consistent with the UI. In the next lesson, we will connect this form to our REST API to persist data to the database.
Up next: Implementing CRUD in the Admin UI
Learn how to scaffold your React admin dashboard by registering a WordPress menu, creating a root container, and mounting your application into the DOM.
Read moreStop scattering fetch calls across your React components. Learn to build a clean service layer to centralize API logic and simplify your WordPress plugin.
Creating a React Form for Submissions
Defining Actions and Reducers
Implementing Resolvers for Data Fetching
Optimizing Performance with Selectors
Handling Complex State Dependencies
Implementing Nonce Verification
Advanced Sanitization Techniques
Input Validation and Error Handling
Protecting Admin Screens
Production Build Pipeline
Debugging React in the WordPress Admin
Building Search and Filter Functionality
Internationalization in React
Managing File Uploads via REST API
Optimizing API Response Times
Working with Date and Time in React
Implementing Drag-and-Drop Sorting
Creating Custom Hooks for API Logic
Integrating with Gutenberg Blocks
Handling Conflict Resolution
Building a Modal Confirmation System
Implementing Activity Logging
Using Webpack Aliases
Unit Testing API Endpoints
Unit Testing React Components
Handling Large Datasets with GraphQL
Implementing Real-time Updates with Web