# How to Use preventDefault in React to Stop Link Navigation and Page Refresh

> Learn how to use preventDefault in React to stop link navigation and page refresh. Call event.preventDefault() in your onClick handler for smooth user experiences.

- Repository: [Meta/react](https://github.com/facebook/react)
- Tags: how-to-guide
- Published: 2026-02-16

---

**Call `event.preventDefault()` inside your `onClick` handler to stop a link's default browser navigation while preserving the `href` attribute for accessibility and SEO.**

React's **SyntheticEvent** system normalizes browser events across environments, providing a consistent `preventDefault()` method identical to the native DOM API. When building single-page applications with the facebook/react repository, preventing default link behavior is essential for client-side routing without full page refreshes.

## Understanding preventDefault in React's SyntheticEvent System

React implements event normalization in [`packages/react-dom-bindings/src/events/SyntheticEvent.js`](https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/events/SyntheticEvent.js), where the `preventDefault()` method sets an internal `defaultPrevented` flag and forwards the call to the underlying native event when available. This architecture ensures cross-browser consistency while maintaining the standard DOM API that developers expect.

The test suite in [`packages/react-dom/src/events/__tests__/SyntheticEvent-test.js`](https://github.com/facebook/react/blob/main/packages/react-dom/src/events/__tests__/SyntheticEvent-test.js) verifies that calling `preventDefault()` correctly marks the event as canceled, which React's event system respects during the bubbling phase.

## The Correct Pattern for preventDefault in React Links

To prevent a link from causing a full-page refresh while maintaining accessibility and SEO benefits, follow this three-step pattern:

1. **Attach an `onClick` handler** to the `<a>` element.
2. **Call `event.preventDefault()`** on the synthetic event passed to the handler.
3. **Execute client-side navigation** using your routing solution or state updates.

```jsx
function SmoothLink() {
  const handleClick = (e) => {
    e.preventDefault();  // Stops the browser's default navigation
    console.log('Navigation prevented, executing custom logic');
  };

  return (
    <a href="/target-page" onClick={handleClick}>
      Click without refreshing
    </a>
  );
}

```

## Practical Implementations of preventDefault in React

### Basic Link That Stays on Page

For links that trigger actions rather than navigation, prevent the default behavior and handle the interaction programmatically:

```jsx
function StayOnPageLink() {
  const handleClick = (e) => {
    e.preventDefault();            // Stops page reload
    console.log('Link clicked, but no navigation');
  };

  return (
    <a href="/unused" onClick={handleClick}>
      Click me – stay on page
    </a>
  );
}

```

### Client-Side Navigation with React Router

When using React Router v6, combine `preventDefault` with the `useNavigate` hook to enable smooth SPA transitions without losing the `href` attribute for accessibility:

```jsx
import { useNavigate } from 'react-router-dom';

function NavLink() {
  const navigate = useNavigate();

  const onClick = (e) => {
    e.preventDefault();            // Cancel native navigation
    navigate('/dashboard');         // Smooth client-side transition
  };

  return (
    <a href="/dashboard" onClick={onClick}>
      Dashboard
    </a>
  );
}

```

### Preventing Form Submission via Link

Links inside forms can inadvertently trigger submissions. Use `preventDefault` to handle the interaction without submitting the form, as demonstrated in [`packages/react-dom/src/__tests__/ReactDOMForm-test.js`](https://github.com/facebook/react/blob/main/packages/react-dom/src/__tests__/ReactDOMForm-test.js):

```jsx
function FormWithLink() {
  const onLinkClick = (e) => {
    e.preventDefault();            // Stop form submission
    // Custom handling logic here
  };

  return (
    <form action="/submit">
      <input type="text" name="name" />
      <a href="/submit" onClick={onLinkClick}>Submit via link</a>
    </form>
  );
}

```

### Using Buttons Instead of Links

When no actual navigation occurs, a `<button type="button">` eliminates the need for `preventDefault` entirely and provides better semantic markup:

```jsx
function ActionButton() {
  const onClick = () => {
    console.log('Button clicked');
  };

  return <button type="button" onClick={onClick}>Do something</button>;
}

```

## How React's SyntheticEvent Handles preventDefault Internally

According to the facebook/react source code, the `preventDefault` implementation resides in [`packages/react-dom-bindings/src/events/SyntheticEvent.js`](https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/events/SyntheticEvent.js). When invoked, it sets the internal `defaultPrevented` property to `true` and proxies the call to the underlying native browser event if one exists.

The test suite in [`packages/react-dom/src/events/__tests__/SyntheticEvent-test.js`](https://github.com/facebook/react/blob/main/packages/react-dom/src/events/__tests__/SyntheticEvent-test.js) validates this behavior, ensuring that `isDefaultPrevented()` returns `true` after the method is called. Additionally, [`packages/react-dom/src/__tests__/ReactDOMForm-test.js`](https://github.com/facebook/react/blob/main/packages/react-dom/src/__tests__/ReactDOMForm-test.js) contains multiple assertions confirming that `preventDefault` successfully stops form submissions, demonstrating its reliability across different event types.

## Summary

- React's **SyntheticEvent** system provides a normalized `preventDefault()` method that works consistently across browsers.
- Always call `event.preventDefault()` inside your `onClick` handler to stop link navigation without removing the `href` attribute.
- Keep valid `href` values for accessibility and SEO, even when handling navigation client-side.
- For React Router applications, combine `preventDefault` with `useNavigate` for smooth SPA transitions.
- Consider using `<button type="button">` instead of `<a>` tags when no actual navigation occurs, eliminating the need for `preventDefault`.

## Frequently Asked Questions

### What is the difference between preventDefault and stopPropagation in React?

**`preventDefault`** stops the browser's default action for an element, such as following a link or submitting a form, without preventing the event from bubbling up to parent elements. **`stopPropagation`** stops the event from bubbling further up the DOM tree but does not prevent the default browser action. In React links, you typically need `preventDefault` to stop navigation, while `stopPropagation` is only necessary if you want to prevent parent click handlers from firing.

### Why does my page still refresh when I use preventDefault in React?

If the page still refreshes after calling `preventDefault`, ensure you are **calling it on the correct event object** passed to your handler, not a stale or cached version. Also verify that your handler is actually being invoked—common mistakes include forgetting to attach the `onClick` prop to the element or having an earlier handler call `event.stopPropagation()` which prevents your handler from running. According to the React source in [`packages/react-dom-bindings/src/events/SyntheticEvent.js`](https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/events/SyntheticEvent.js), `preventDefault` must be called before the event handler returns for the flag to take effect.

### Should I use a button or a link when implementing preventDefault in React?

Use an **`<a>` tag** when the action represents navigation to another resource, even if handled client-side, because it provides proper semantics for screen readers, keyboard accessibility, and SEO crawling. Use a **`<button type="button">`** when triggering an action on the current page, such as opening a modal or submitting data via API, because buttons have correct semantic meaning for actions rather than navigation, and they do not require `preventDefault` to prevent page refreshes.

### How do I test preventDefault behavior in React components?

Test `preventDefault` by **spying on the event object** passed to your handler and asserting that the method was called. In React Testing Library, you can verify that navigation did not occur by checking that `window.location` remains unchanged or that your navigation mock, such as `useNavigate` from React Router, was called instead of a full page reload. The React test suite in [`packages/react-dom/src/events/__tests__/SyntheticEvent-test.js`](https://github.com/facebook/react/blob/main/packages/react-dom/src/events/__tests__/SyntheticEvent-test.js) demonstrates asserting `isDefaultPrevented()` to verify the internal state change after calling `preventDefault`.