nextjs - 💡(How to fix) Fix [Bug]: Client Component onClick events fail to fire on iOS Safari (Next.js 16.2.1) [13 comments, 4 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#91908Fetched 2026-04-08 01:30:05
View on GitHub
Comments
13
Participants
4
Timeline
48
Reactions
0
Author
Assignees
Timeline (top)
subscribed ×15mentioned ×14commented ×13assigned ×1

Code Example

'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}

---

OS: iOS (Tested on iPhone)
Browser: Safari
Next.js Version: 16.2.1
Node.js Version: 24.1.4
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/KamingLo/nextjs-boilerplate

To Reproduce

Create a fresh Next.js project using npx [email protected].

Create a simple counter Client Component in the main page:

TypeScript

'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}

Deploy or run the development server.

Open the application using Safari on an iPhone.

Tap the "Increment" button. The count remains 0 and does not update.

Current vs. Expected behavior

In Next.js version 16.2.1, basic interactive elements (like a button with an onClick handler) inside a Client Component do not register touch events on iOS Safari. The component renders visually, but the state fails to update upon tapping.

This issue severely impacts mobile-first development, as the exact same code works perfectly on desktop browsers (like Chrome on Windows) and functions flawlessly when downgraded to Next.js 15.

Tapping a button with an attached onClick event in a Client Component should successfully trigger the state update and reflect the new state in the UI on iOS Safari, just as it does on desktop environments.

Provide environment information

OS: iOS (Tested on iPhone)
Browser: Safari
Next.js Version: 16.2.1
Node.js Version: 24.1.4

Which area(s) are affected? (Select all that apply)

Loading UI and Streaming

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

Downgrading the project to Next.js 16.1.6 immediately resolves the issue, and the button becomes fully responsive on iOS Safari. This suggests a potential issue with how hydration or client-side rendering is handled specifically for WebKit mobile environments in version 16.2.1

extent analysis

Fix Plan

The fix involves adding a touchstart event listener to the button element.

  • Update the Counter component to include the touchstart event:
'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  const handleIncrement = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={handleIncrement} onTouchStart={handleIncrement}>
        Increment
      </button>
    </div>
  );
}

Alternatively, you can also use a library like react-tap-event-plugin to handle touch events.

Verification

To verify the fix, run the development server and open the application on an iPhone using Safari. Tap the "Increment" button to ensure the count updates correctly.

Extra Tips

  • This issue is specific to WebKit mobile environments, so ensure to test on iOS Safari.
  • Downgrading to Next.js 16.1.6 is a temporary workaround, but applying the fix above is recommended for long-term compatibility.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING