In my decade-plus experience as a developer, I’ve found that handling cancellation actions effectively is crucial for creating user-friendly React applications. Whether you’re building forms, modals, or API requests, a well-implemented cancel button improves user experience significantly.
In this tutorial, I will walk you through different methods to implement cancel buttons in React applications. These approaches range from simple UI cancellations to more complex scenarios involving API request cancellation.
Let’s get started..
Method 1: Basic Cancel Button for Forms
The most common use case for cancel buttons is in forms where users need the option to discard their inputs.
Here’s a simple implementation:
import React, { useState } from 'react';
function UserForm({ onSubmit, onCancel }) {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
onSubmit({ name, email });
};
const handleCancel = () => {
// Clear form data
setName('');
setEmail('');
// Call the onCancel prop if provided
if (onCancel) onCancel();
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Name:</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<div>
<label>Email:</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
<button type="submit">Submit</button>
<button type="button" onClick={handleCancel}>Cancel</button>
</div>
</form>
);
}You can see the output in the screenshot below.

In this example, our cancel button:
- Uses
type="button"to prevent form submission - Clears form data
- Triggers an optional callback function
Read How to Handle Events in React JS
Method 2: Cancel Button with React Router
When working with multi-page forms or workflows, you might want to navigate away when a user cancels. React Router makes this easy:
If you haven’t installed React Router, run this in your terminal:
npm install react-router-domimport React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
function RegistrationForm() {
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: ''
});
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
// Process form submission
console.log('Form submitted:', formData);
navigate('/success');
};
const handleCancel = () => {
// Confirm before navigating away
if (window.confirm('Are you sure you want to cancel? Your data will be lost.')) {
navigate('/home');
}
};
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prevData => ({
...prevData,
[name]: value
}));
};
return (
<form onSubmit={handleSubmit}>
<h2>Create Account</h2>
{/* Form fields */}
<div>
<label>First Name:</label>
<input
type="text"
name="firstName"
value={formData.firstName}
onChange={handleChange}
/>
</div>
<div>
<label>Last Name:</label>
<input
type="text"
name="lastName"
value={formData.lastName}
onChange={handleChange}
/>
</div>
<div>
<label>Email:</label>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
</div>
<div>
<button type="submit">Create Account</button>
<button type="button" onClick={handleCancel}>Cancel</button>
</div>
</form>
);
}Write this code in the index.js file:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './index.css'; // optional, for styling
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);You can see the output in the screenshot below.

This is the output you will get when you press the create account button.

This is the output you will get when you press the cancel button.

This implementation adds a confirmation dialog to prevent accidental data loss, which is particularly important for longer forms.
Method 3: Modal Cancel Button
Modals are perfect for focused tasks, and a cancel button is essential for closing them:
import React, { useState } from 'react';
import './Modal.css';
function Modal({ isOpen, onClose, onSubmit, title }) {
const [input, setInput] = useState('');
if (!isOpen) return null;
const handleSubmit = (e) => {
e.preventDefault();
onSubmit(input);
setInput('');
};
const handleCancel = () => {
setInput('');
onClose();
};
return (
<div className="modal-overlay">
<div className="modal-content">
<h2>{title}</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Enter your data"
/>
<div className="modal-buttons">
<button type="submit">Submit</button>
<button type="button" onClick={handleCancel}>Cancel</button>
</div>
</form>
</div>
</div>
);
}
// Usage in a parent component
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
const [result, setResult] = useState('');
const handleSubmit = (data) => {
setResult(data);
setIsModalOpen(false);
};
return (
<div className="app">
<h1>Modal Example</h1>
<button onClick={() => setIsModalOpen(true)}>Open Modal</button>
{result && <p>You submitted: {result}</p>}
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onSubmit={handleSubmit}
title="Enter Information"
/>
</div>
);
}This modal implementation includes a cancel button that closes the modal and resets any input, providing a clean slate for the next interaction.
Method 4: Cancel API Requests with Axios
One of the most powerful cancel button implementations is for API requests. Here’s how to do it with Axios:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function SearchComponent() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const searchUsers = async (searchQuery) => {
setLoading(true);
setError(null);
// Create a cancel token
const cancelToken = axios.CancelToken.source();
try {
const response = await axios.get(
`https://api.github.com/search/users?q=${searchQuery}`,
{ cancelToken: cancelToken.token }
);
setResults(response.data.items);
setLoading(false);
return cancelToken;
} catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled:', error.message);
} else {
setError('Error fetching data. Please try again.');
setLoading(false);
}
return cancelToken;
}
};
const handleSearch = (e) => {
e.preventDefault();
if (query.trim()) {
searchUsers(query);
}
};
const handleCancel = (cancelTokenSource) => {
if (cancelTokenSource) {
cancelTokenSource.cancel('User canceled the request');
setLoading(false);
}
};
return (
<div>
<h2>GitHub User Search</h2>
<form onSubmit={handleSearch}>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search GitHub users..."
/>
<button type="submit">Search</button>
{loading && (
<button
type="button"
onClick={() => handleCancel(searchUsers.cancelToken)}
>
Cancel
</button>
)}
</form>
{loading && <p>Loading...</p>}
{error && <p className="error">{error}</p>}
<ul>
{results.map(user => (
<li key={user.id}>{user.login}</li>
))}
</ul>
</div>
);
}This implementation is particularly useful for search interfaces where users might want to cancel a request if they change their mind or make a typo.
Method 5: Use AbortController for Fetch API
If you’re using the native Fetch API instead of Axios, you can implement cancellation with AbortController:
import React, { useState, useRef } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const abortControllerRef = useRef(null);
const fetchData = async () => {
// Reset states
setLoading(true);
setError(null);
setData(null);
// Create a new AbortController
abortControllerRef.current = new AbortController();
const { signal } = abortControllerRef.current;
try {
// This example uses the US Census API
const response = await fetch(
'https://api.census.gov/data/2020/acs/acs5?get=NAME,B01001_001E&for=state:*',
{ signal }
);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setData(result);
setLoading(false);
} catch (err) {
if (err.name === 'AbortError') {
console.log('Fetch aborted');
} else {
setError('Error fetching data: ' + err.message);
}
setLoading(false);
}
};
const handleCancel = () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
setLoading(false);
}
};
return (
<div>
<h2>US State Population Data</h2>
<div>
<button onClick={fetchData} disabled={loading}>
Fetch Data
</button>
{loading && (
<button onClick={handleCancel}>
Cancel
</button>
)}
</div>
{loading && <p>Loading...</p>}
{error && <p className="error">{error}</p>}
{data && (
<div>
<h3>State Populations:</h3>
<ul>
{data.slice(1).map((state, index) => (
<li key={index}>
{state[0]}: {parseInt(state[1]).toLocaleString()} people
</li>
))}
</ul>
</div>
)}
</div>
);
}This example fetches US Census data and allows users to cancel the request if it’s taking too long.
Styling Cancel Buttons for Better UX
The visual design of cancel buttons is crucial for user experience. A common pattern is to make cancel buttons visually distinct from primary action buttons to prevent accidental clicks. Here’s how I style cancel buttons in my React projects:
import React from 'react';
import './Button.css';
function ActionButtons({ onSubmit, onCancel }) {
return (
<div className="button-container">
<button
className="button primary-button"
onClick={onSubmit}
>
Submit
</button>
<button
className="button cancel-button"
onClick={onCancel}
>
Cancel
</button>
</div>
);
}And the corresponding CSS:
.button-container {
display: flex;
gap: 10px;
margin-top: 20px;
}
.button {
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
}
.primary-button {
background-color: #0066cc;
color: white;
border: 1px solid #0066cc;
}
.primary-button:hover {
background-color: #0052a3;
}
.cancel-button {
background-color: white;
color: #333;
border: 1px solid #ccc;
}
.cancel-button:hover {
background-color: #f1f1f1;
}This styling approach makes the cancel button less prominent while still accessible, reducing the chances of users accidentally discarding their work.
Implementing effective cancel buttons in React applications is more than just adding a button element. It requires thoughtful handling of various states, resources, and user expectations.
Related tutorials:
- How to Upload Files in React JS
- Set Up React.js Environment and Create Your First React App
- Form Validation in React.js
- Create Tables in React Using react-data-table-component

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.