diff --git a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp
index c1c8d70167c0..e3d7b7f440cc 100644
--- a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp
+++ b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp
@@ -34,6 +34,15 @@ namespace facebook::react {
namespace {
+/**
+ * Default `durationThreshold` (in milliseconds) applied to `event` entries when
+ * the JS API does not provide an explicit value. Per the W3C Event Timing
+ * spec, observers for `event` entries default to a 104ms threshold:
+ * https://www.w3.org/TR/event-timing/#sec-modifications-perf-timeline
+ */
+constexpr HighResDuration DEFAULT_EVENT_DURATION_THRESHOLD =
+ HighResDuration::fromMilliseconds(104);
+
class PerformanceObserverWrapper : public jsi::NativeState {
public:
explicit PerformanceObserverWrapper(
@@ -337,7 +346,7 @@ void NativePerformance::observe(
}
auto durationThreshold =
- options.durationThreshold.value_or(HighResDuration::zero());
+ options.durationThreshold.value_or(DEFAULT_EVENT_DURATION_THRESHOLD);
// observer of type multiple
if (options.entryTypes.has_value()) {
diff --git a/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js b/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js
index 398ecd712ce7..ab89fd1d4f3a 100644
--- a/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js
+++ b/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js
@@ -38,7 +38,7 @@ describe('Event Timing API', () => {
const callback = jest.fn();
const observer = new PerformanceObserver(callback);
- observer.observe({entryTypes: ['event']});
+ observer.observe({type: 'event', durationThreshold: 0});
const root = Fantom.createRoot();
Fantom.runTask(() => {
@@ -79,7 +79,7 @@ describe('Event Timing API', () => {
const callback = jest.fn();
const observer = new PerformanceObserver(callback);
- observer.observe({entryTypes: ['event']});
+ observer.observe({type: 'event', durationThreshold: 0});
const SIMULATED_PROCESSING_DELAY = 50;
@@ -132,7 +132,7 @@ describe('Event Timing API', () => {
const callback = jest.fn();
const observer = new PerformanceObserver(callback);
- observer.observe({entryTypes: ['event']});
+ observer.observe({type: 'event', durationThreshold: 0});
function MyComponent() {
const [count, setCount] = useState(0);
@@ -188,7 +188,7 @@ describe('Event Timing API', () => {
const callback = jest.fn();
const observer = new PerformanceObserver(callback);
- observer.observe({entryTypes: ['event']});
+ observer.observe({type: 'event', durationThreshold: 0});
let eventTimeStamp;
@@ -341,6 +341,52 @@ describe('Event Timing API', () => {
expect(callback).toHaveBeenCalledTimes(1);
});
+ it('defaults to 104ms for event entries per W3C spec', () => {
+ const callback = jest.fn();
+
+ const observer = new PerformanceObserver(callback);
+ observer.observe({type: 'event'});
+
+ let forceDelay = false;
+
+ function MyComponent() {
+ const [count, setCount] = useState(0);
+
+ return (
+ {
+ if (forceDelay) {
+ sleep(104);
+ }
+ setCount(count + 1);
+ }}>
+ {count}
+
+ );
+ }
+
+ const root = Fantom.createRoot();
+ Fantom.runTask(() => {
+ root.render();
+ });
+
+ const element = nullthrows(
+ root.document.documentElement.firstElementChild,
+ );
+
+ expect(callback).not.toHaveBeenCalled();
+
+ Fantom.dispatchNativeEvent(element, 'click');
+
+ expect(callback).toHaveBeenCalledTimes(0);
+
+ forceDelay = true;
+
+ Fantom.dispatchNativeEvent(element, 'click');
+
+ expect(callback).toHaveBeenCalledTimes(1);
+ });
+
it('throws when used together with `entryTypes`', () => {
const observer = new PerformanceObserver(() => {});
diff --git a/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js b/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js
index 442f6a736113..24c9e1bc9be5 100644
--- a/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js
+++ b/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js
@@ -143,7 +143,7 @@ function PerformanceObserverEventTimingExample(): React.Node {
setEntries(newEntries);
});
- observer.observe({type: 'event'});
+ observer.observe({type: 'event', durationThreshold: 0});
return () => observer.disconnect();
}, []);