diff --git a/packages-private/dts-test/h.test-d.ts b/packages-private/dts-test/h.test-d.ts
index a199e14ced9..ebe127ff663 100644
--- a/packages-private/dts-test/h.test-d.ts
+++ b/packages-private/dts-test/h.test-d.ts
@@ -39,6 +39,51 @@ describe('h inference w/ element', () => {
     onClick: e => {
       expectType<MouseEvent>(e)
     },
+    onClickCapture: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickCaptureOnce: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickCaptureOncePassive: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickCapturePassive: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickCapturePassiveOnce: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickOnce: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickOnceCapture: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickOnceCapturePassive: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickOncePassive: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickOncePassiveCapture: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickPassive: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickPassiveCapture: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickPassiveCaptureOnce: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickPassiveOnce: e => {
+      expectType<MouseEvent>(e)
+    },
+    onClickPassiveOnceCapture: e => {
+      expectType<MouseEvent>(e)
+    },
   })
   h('input', {
     onFocus(e) {
diff --git a/packages-private/dts-test/tsx.test-d.tsx b/packages-private/dts-test/tsx.test-d.tsx
index 0cd380f0447..c1c6fc75ec6 100644
--- a/packages-private/dts-test/tsx.test-d.tsx
+++ b/packages-private/dts-test/tsx.test-d.tsx
@@ -84,6 +84,52 @@ expectType<JSX.Element>(
       // infer correct event type
       expectType<EventTarget | null>(e.target)
     }}
+    onInputCapture={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputCaptureOnce={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputCaptureOncePassive={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputCapturePassive={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputCapturePassiveOnce={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputOnce={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputOnceCapture={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputOnceCapturePassive={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputOncePassive={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputOncePassiveCapture={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputPassive={e => {
+      // infer correct event type
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputPassiveCapture={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputPassiveCaptureOnce={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputPassiveOnce={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
+    onInputPassiveOnceCapture={e => {
+      expectType<EventTarget | null>(e.target)
+    }}
   />,
 )
 
diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts
index 93e7fd9bc88..b3b4c8eef06 100644
--- a/packages/runtime-core/src/h.ts
+++ b/packages/runtime-core/src/h.ts
@@ -75,8 +75,14 @@ interface Constructor<P = any> {
   new (...args: any[]): { $props: P }
 }
 
+type CombineModifiers<T extends string, U extends string = T> = T extends any
+  ? T | `${T}${CombineModifiers<Exclude<U, T>>}`
+  : never
+
+type EventModifiers = CombineModifiers<'Capture' | 'Once' | 'Passive'> | ''
+
 type HTMLElementEventHandler = {
-  [K in keyof HTMLElementEventMap as `on${Capitalize<K>}`]?: (
+  [K in keyof HTMLElementEventMap as `on${Capitalize<K>}${EventModifiers}`]?: (
     ev: HTMLElementEventMap[K],
   ) => any
 }
diff --git a/packages/runtime-dom/src/jsx.ts b/packages/runtime-dom/src/jsx.ts
index 5292441cde9..f32d80d31d2 100644
--- a/packages/runtime-dom/src/jsx.ts
+++ b/packages/runtime-dom/src/jsx.ts
@@ -252,7 +252,7 @@ export type StyleValue =
   | CSSProperties
   | Array<StyleValue>
 
-export interface HTMLAttributes extends AriaAttributes, EventHandlers<Events> {
+export interface HTMLAttributes extends AriaAttributes, EventHandlers {
   innerHTML?: string
 
   class?: any
@@ -808,7 +808,7 @@ export interface WebViewHTMLAttributes extends HTMLAttributes {
   webpreferences?: string
 }
 
-export interface SVGAttributes extends AriaAttributes, EventHandlers<Events> {
+export interface SVGAttributes extends AriaAttributes, EventHandlers {
   innerHTML?: string
 
   /**
@@ -1384,10 +1384,14 @@ export interface Events {
   onTransitionstart: TransitionEvent
 }
 
-type EventHandlers<E> = {
-  [K in keyof E]?: E[K] extends (...args: any) => any
-    ? E[K]
-    : (payload: E[K]) => void
+type CombineModifiers<T extends string, U extends string = T> = T extends any
+  ? T | `${T}${CombineModifiers<Exclude<U, T>>}`
+  : never
+
+type EventModifiers = CombineModifiers<'Capture' | 'Once' | 'Passive'> | ''
+
+type EventHandlers = {
+  [K in keyof Events as `${K}${EventModifiers}`]?: (payload: Events[K]) => void
 }
 
 import type { VNodeRef } from '@vue/runtime-core'