Button with Loading Spinner
Reusable React button component that shows a spinner when performing an async action.
When actions take time—like submitting a form or saving settings—users appreciate visual feedback. This button component accepts an onClick
callback that returns a promise; while the promise is pending, it disables itself and displays a spinner. It’s simple, accessible, and easy to reuse across your app.
import { useState } from "react";
interface LoadingButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
onClick: () => Promise<unknown>;
children: React.ReactNode;
}
export function LoadingButton({
onClick,
children,
...rest
}: LoadingButtonProps) {
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
try {
await onClick();
} finally {
setLoading(false);
}
};
return (
<button onClick={handleClick} disabled={loading} {...rest}>
{loading ? <span className="spinner" aria-label="Loading…" /> : children}
</button>
);
}
You can style the .spinner
class however you like, perhaps with CSS animations. Use LoadingButton
whenever you need to show progress without rewriting the same boilerplate each time.