In a React onSubmit or onClick handler, why does `return false` not stop the browser's default behaviour, and what do you write instead?
answer
- React ignores what a handler returns
- the idiom belongs to jQuery and inline attributes
- cancel with a method, not a value
- two separate calls, not one
- e.preventDefault()
basics
~10 sReact ignores a handler's return value entirely. Returning false only cancels defaults in inline HTML attributes and jQuery handlers. In React you call e.preventDefault(), and e.stopPropagation() separately if you also want to stop bubbling.
solid answer
~40 sReact never inspects what a handler returns, so `return false` is dead code — the form still submits and the page still navigates. That idiom comes from two other worlds: an inline HTML attribute like `onclick="return false"`, where the returned value *is* the cancellation protocol, and jQuery, where returning false calls `preventDefault()` **and** `stopPropagation()` for you. In React they are two separate, explicit calls on the SyntheticEvent: `e.preventDefault()` cancels the browser's default action, `e.stopPropagation()` stops the event reaching ancestor handlers, and neither implies the other. The one React 19 case where you do not call preventDefault yourself is passing a function to a form's `action` prop — React then owns the submission rather than letting the browser navigate.
code
javascript · 14 linesfunction SearchForm() {
function handleSubmit(e) {
e.preventDefault(); // returning false here would change nothing
const data = new FormData(e.currentTarget);
console.log(data.get('q'));
}
return (
<form onSubmit={handleSubmit}>
<input name="q" />
<button type="submit">Search</button>
</form>
);
}go deeper
Say plainly that React ignores the return value and that you cancel with e.preventDefault(). Know that stopping bubbling is a separate call.
Explain where the return false idiom comes from — inline HTML attributes and jQuery's double shorthand — and state that preventDefault and stopPropagation solve unrelated problems.
Bring the cancelable check and the async trap: preventDefault only works during dispatch on a cancelable event, so a call after an await is silently useless. Question whether the element needed a default suppressed at all.
Argue the API design: jQuery's overloaded return value coupled two independent concerns and produced quiet bugs, which is exactly why React kept them as explicit separate calls with matching isDefaultPrevented / isPropagationStopped predicates.
## The mechanism React calls your handler and throws the return value away. There is no protocol by which a returned value means anything, so `return false` is a no-op statement that happens to also end the function early. ```js function handleSubmit(e) { console.log('submitting'); return false; // React does not look at this — the page still navigates } ``` To cancel, you call a method on the event: ```js function handleSubmit(e) { e.preventDefault(); // ... your own submit logic } ``` ## Where the myth comes from Two older conventions taught `return false`, and both are real — just not React. The first is the **inline HTML attribute handler**: `<a href="/x" onclick="return false">`. The attribute's body is compiled into a function whose return value the browser genuinely consults; returning false cancels the default action. Note that this is a property of attribute handlers only — a listener added with `addEventListener` ignores its return value too, exactly like React. The second is **jQuery**. jQuery deliberately made `return false` shorthand for calling `preventDefault()` *and* `stopPropagation()`. That double meaning is the reason the idiom spread, and the reason it caused subtle bugs even in jQuery: people who wanted only one of the two effects silently got both. React chose neither convenience. It keeps the two operations separate and explicit. ## preventDefault and stopPropagation are unrelated These answer two different questions: - `e.preventDefault()` — "do not perform the browser's built-in action for this event." A form does not submit and navigate; an anchor does not follow its href; a checkbox does not toggle; a context menu does not open. - `e.stopPropagation()` — "do not let this event continue to handlers on ancestor elements." It has nothing to do with the default action; a link whose click you stopped from propagating still navigates. Calling one when you meant the other is one of the most common React event bugs. A candidate who explains this distinction cleanly has effectively answered the question. React also lets you *ask* about the result afterwards: `e.isDefaultPrevented()` and `e.isPropagationStopped()` report whether an earlier handler already did either. ## Which events even have a default to prevent `preventDefault()` does nothing unless the event is cancelable — `e.cancelable` tells you. Submitting a form, clicking an anchor or a checkbox, dropping a dragged item, and opening a context menu are all cancelable. Many others are not: a `focus` or a `scroll` has no default action you can veto this way. ## The React 19 exception worth knowing If you pass a function to a form's `action` prop, React handles the submission itself and does not let the browser navigate, so there is no `preventDefault()` for you to write: ```js <form action={async (formData) => { await save(formData); }}> ``` The classic `onSubmit={handleSubmit}` form still requires the explicit call. Both are current React 19; the difference is who owns the submission. ## The nuance behind the anchor case A very common variant is "I have `<a href="#">` with an onClick and the page jumps to the top." That jump is the default action of following the fragment, so `e.preventDefault()` is the fix — but the better fix is usually to stop misusing an anchor. If the element performs an action rather than navigating, it should be a `<button type="button">`, which has no navigation default at all and is correct for assistive technology. Reaching for preventDefault to suppress an element's natural behaviour is often a sign the wrong element was chosen.
- If preventDefault and stopPropagation are separate, which one do you need to stop a link from navigating?`preventDefault()`. Navigation is the anchor's default action, so cancelling it is what keeps the page put. `stopPropagation()` only stops ancestor handlers from seeing the click — the browser would still follow the href. Needing preventDefault on an anchor that never navigates is usually a hint the element should have been a `<button type="button">`.
- How can a handler tell that some other handler already called preventDefault on the same event?React's SyntheticEvent exposes `isDefaultPrevented()`, and the DOM-standard `defaultPrevented` property is on there too. Both let a later handler in the dispatch skip work that a component closer to the target already claimed. There is a matching `isPropagationStopped()` for the other operation.
- Does preventDefault always work? When does the call do nothing?Only cancelable events respond to it — `e.cancelable` reports whether this one does. Events such as focus or scroll have no vetoable default, so the call is silently ignored. The same is true if the default has already happened: preventDefault must be called during dispatch, not later from an async callback.
saying these in an interview costs you the question
- Says return false cancels the default like in jQuery
- Thinks preventDefault also stops the event bubbling
- Uses stopPropagation to stop a link navigating
- Calls preventDefault asynchronously after an await
- Believes React warns you when a handler returns false