A React cancel button often looks simple until you add real application behavior. I have built task dashboards where Cancel needs to discard a task edit, close a side panel, restore form values, or stop an API request already in progress.
The key is deciding what “cancel” means in the current component. A button that only clears one input needs a different approach than a button that abandons a full task-edit workflow.
Below, I will show five practical React cancel button methods using a task dashboard example.
React Cancel Button Basics
In React 18 and later, you will usually build a cancel button inside a functional component. The button runs a function through the onClick event, and that function updates component state, calls a parent callback, or cancels an active request.
If you are new to click handling, see this guide on handling events in React. The important idea is simple: your button should trigger a clear action rather than trying to change the page directly.
Here is the smallest possible React cancel button:
function TaskEditor() {
function handleCancel() {
console.log("Task editing cancelled");
}
return (
<button type="button" onClick={handleCancel}>
Cancel
</button>
);
}The type="button" matters when the button sits inside a form. Without it, a browser may treat the button as a submit button by default.
The onClick prop receives the handleCancel function. React runs that function only when the user clicks Cancel.
1. Reset Local State
Use this method when users edit values stored in local useState variables. It works well for a task title, description, priority field, or quick-edit panel.
A controlled input gets its value from React state. You must reset that state when the user cancels. You can learn more about this pattern in this guide to React controlled components.
import { useState } from "react";
function TaskEditor() {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
function handleCancel() {
setTitle("");
setDescription("");
}
return (
<section>
<label>
Task title
<input
value={title}
onChange={(event) => setTitle(event.target.value)}
/>
</label>
<label>
Description
<textarea
value={description}
onChange={(event) => setDescription(event.target.value)}
/>
</label>
<button type="button" onClick={handleCancel}>
Cancel
</button>
</section>
);
}I executed the above example code and added the screenshot below.

This React cancel button clears both state values. Since the inputs use value={title} and value={description}, React immediately re-renders them as empty.
Use this approach for a new-task form where Cancel should remove unfinished user input.
Reset to Original Values
In edit screens, clearing fields usually feels wrong. Users expect Cancel to restore the saved task values instead.
import { useState } from "react";
function TaskEditor({ task }) {
const [title, setTitle] = useState(task.title);
const [status, setStatus] = useState(task.status);
function handleCancel() {
setTitle(task.title);
setStatus(task.status);
}
return (
<section>
<input
value={title}
onChange={(event) => setTitle(event.target.value)}
/>
<select
value={status}
onChange={(event) => setStatus(event.target.value)}
>
<option value="Open">Open</option>
<option value="In Progress">In Progress</option>
<option value="Done">Done</option>
</select>
<button type="button" onClick={handleCancel}>
Cancel changes
</button>
</section>
);
}I executed the above example code and added the screenshot below.

This version uses incoming props as the source of truth. The cancel handler restores local state from the last saved task.
2. Use a Native Form Reset
A native form reset button works for simple uncontrolled forms. An uncontrolled input lets the browser manage its current value instead of React state.
function NewTaskForm() {
function handleCancel() {
console.log("The form returned to its original HTML values");
}
return (
<form onReset={handleCancel}>
<label>
Task title
<input name="title" defaultValue="" />
</label>
<label>
Priority
<select name="priority" defaultValue="Medium">
<option>Low</option>
<option>Medium</option>
<option>High</option>
</select>
</label>
<button type="reset">Cancel</button>
</form>
);
}The type="reset" button resets fields to their defaultValue values. The onReset handler runs after the user clicks it.
This option stays clean when your form has a few fields and no React-managed draft data. For controlled forms, do not rely on type="reset" alone. React will reapply the state values during the next render.
For controlled forms, use state updates instead. This detailed React form reset example can help when you need to reset inputs, validation messages, and submit states together.
3. Close a Modal or Edit Panel
A cancel button often exists to close an interface, not to erase data. This is common in task dashboards, admin panels, and table row editors.
Use conditional rendering to show the editor only when React state says it is open.
import { useState } from "react";
function TaskDashboard() {
const [isEditorOpen, setIsEditorOpen] = useState(false);
function handleCancel() {
setIsEditorOpen(false);
}
return (
<main>
<button type="button" onClick={() => setIsEditorOpen(true)}>
Add task
</button>
{isEditorOpen && (
<section role="dialog" aria-modal="true">
<h2>Create task</h2>
<input placeholder="Enter a task title" />
<button type="button" onClick={handleCancel}>
Cancel
</button>
</section>
)}
</main>
);
}The expression {isEditorOpen && (...)} means React renders the editor only when isEditorOpen is true. Clicking Cancel sets it to false, so React removes the editor from the page.
This is often the best React cancel button method for dialogs because it keeps the close logic obvious. You can also add a separate reset handler if the modal should discard draft values before closing.
4. Call a Parent Function Through Props
Use this pattern when a child component displays the button, but the parent owns the data or visibility state. This keeps state management predictable in larger applications.
For example, a task dashboard may render a reusable TaskEditor component. The dashboard decides whether that editor stays open.
function TaskEditor({ task, onCancel }) {
return (
<section>
<h2>Edit: {task.title}</h2>
<input defaultValue={task.title} />
<button type="button" onClick={onCancel}>
Cancel
</button>
</section>
);
}import { useState } from "react";
function TaskDashboard() {
const [selectedTask, setSelectedTask] = useState(null);
function handleCancelEdit() {
setSelectedTask(null);
}
return (
<main>
<button
type="button"
onClick={() =>
setSelectedTask({ id: 1, title: "Prepare release notes" })
}
>
Edit task
</button>
{selectedTask && (
<TaskEditor
task={selectedTask}
onCancel={handleCancelEdit}
/>
)}
</main>
);
}The parent passes handleCancelEdit through the props object as onCancel. The child does not need to know how the dashboard stores its selected task.
I use this approach frequently for reusable modal, drawer, and editor components. See how to pass a function to a child React component for a deeper explanation of this parent-child pattern.
5. Cancel an API Request
Use this method when a Cancel button should stop a pending network request. This matters in search screens, report generators, file uploads, and API-driven task dashboards.
Modern browsers support AbortController, which lets you stop a request by calling abort().
import { useRef, useState } from "react";
function TaskImport() {
const [isLoading, setIsLoading] = useState(false);
const [message, setMessage] = useState("");
const controllerRef = useRef(null);
async function loadTasks() {
const controller = new AbortController();
controllerRef.current = controller;
setIsLoading(true);
setMessage("");
try {
const response = await fetch("/api/tasks", {
signal: controller.signal,
});
const tasks = await response.json();
setMessage(`${tasks.length} tasks loaded`);
} catch (error) {
if (error.name === "AbortError") {
setMessage("Task loading cancelled");
} else {
setMessage("Could not load tasks");
}
} finally {
setIsLoading(false);
controllerRef.current = null;
}
}
function handleCancel() {
controllerRef.current?.abort();
}
return (
<section>
<button type="button" onClick={loadTasks} disabled={isLoading}>
Load tasks
</button>
{isLoading && (
<button type="button" onClick={handleCancel}>
Cancel loading
</button>
)}
<p>{message}</p>
</section>
);
}The useRef hook stores the current controller without causing an extra render. The optional chaining operator in controllerRef.current?.abort() safely runs abort() only when a request exists.
The finally block always turns off loading, whether the request succeeds, fails, or gets cancelled. If you load external task data, also review this guide on fetching and displaying API data in React.
Pro Tip: I’ve found that a cancel button should reset the same draft state that the Save button reads. If you keep a copied task object in useState, reset it with a new object such as setDraftTask({ ...task }) instead of changing properties directly.
Things to Keep in Mind
- Use type=”button”: Add this to Cancel buttons inside forms so they do not accidentally submit the form.
- Reset controlled values with state: A native form reset does not reliably clear inputs controlled by useState.
- Avoid direct state mutation: Never change an object or array already stored in React state. Create a new object with the spread operator or a new array before updating state.
- Keep cancellation local when possible: Let a child call an
onCancelprop, while the parent owns shared modal, route, or selected-task state. - Handle pending requests carefully: Keep loading state accurate after calling
abort(), so users do not see a disabled button forever. - Prevent stale drafts: When a user opens a different task, initialize the editor with that task’s current values instead of preserving an older draft.
Frequently Asked Questions
How do I create a cancel button in React?
Add a button with type="button" and an onClick handler. The handler can reset state, close a component, call a parent function, or abort a request.
Why does my Cancel button submit the form?
A <button> inside a form behaves as a submit button unless you specify its type. Set type="button" for a cancel action or type="reset" for a simple native reset.
How do I reset a controlled React form?
Reset each value stored in useState. For example, call setTitle("") and setDescription(""), or restore values from the original task object.
Should a React cancel button close the modal and reset fields?
Usually, yes. Users expect Cancel to discard unsaved edits and leave the editor. Reset the local draft state first, then set the modal visibility state to false.
Can a child component handle Cancel in React?
Yes. Pass an onCancel callback from the parent through props, then use it in the child button’s onClick handler. This pattern keeps shared state in one place.
How do I cancel a fetch request in React?
Create an AbortController, pass its signal to fetch(), and call controller.abort() from your cancel handler. Catch the resulting AbortError so your UI can show a helpful cancellation message.
A React cancel button works best when its behavior matches the user’s current task. Reset local state for forms, use parent callbacks for shared UI, and abort requests only when the user truly needs to stop network work.
Start with a clear cancel action and keep state updates immutable. I hope you found this article helpful.
You May Also Like
- How React component state management works
- How to use conditional rendering in React
- React component key prop explained
- How to prevent unnecessary React re-renders
- How to handle a React component unmount

Bijay Kumar is an experienced Python and AI professional who enjoys helping developers learn modern technologies through practical tutorials and examples. His expertise includes Python development, Machine Learning, Artificial Intelligence, automation, and data analysis using libraries like Pandas, NumPy, TensorFlow, Matplotlib, SciPy, and Scikit-Learn. At PythonGuides.com, he shares in-depth guides designed for both beginners and experienced developers. More about us.