--- title: Use withModifiers for Event Modifiers in Render Functions impact: MEDIUM impactDescription: Manual modifier implementation is error-prone; use withModifiers helper type: best-practice tags: [vue3, render-function, events, modifiers] --- # Use withModifiers for Event Modifiers in Render Functions **Impact: MEDIUM** - When using render functions, event modifiers like `.stop`, `.prevent`, or `.self` require special handling. Use Vue's `withModifiers` helper function instead of manually implementing modifier logic, which is error-prone. In templates, you can use modifiers like `@click.stop.prevent`. In render functions, you must either use camelCase concatenation for simple modifiers or the `withModifiers` helper for more complex ones. ## Task Checklist - [ ] Use camelCase concatenation for capture, once, and passive modifiers - [ ] Use `withModifiers()` helper for stop, prevent, self, and key modifiers - [ ] Import `withModifiers` from 'vue' when needed - [ ] Combine multiple modifiers by passing them as an array **Incorrect:** ```javascript import { h } from 'vue' export default { setup() { const handleClick = (e) => { // WRONG: Manual modifier implementation is error-prone e.stopPropagation() e.preventDefault() // ... actual handler logic } return () => h('button', { onClick: handleClick }, 'Click') } } ``` ```javascript // WRONG: Forgetting to handle modifier in complex scenarios const handleDivClick = (e) => { // Intended: only trigger when clicking div itself, not children // This manual check is easy to get wrong if (e.target !== e.currentTarget) return // ... } ``` **Correct:** ```javascript import { h, withModifiers } from 'vue' export default { setup() { const handleClick = () => { console.log('clicked!') } return () => h('button', { // CORRECT: Use withModifiers for stop and prevent onClick: withModifiers(handleClick, ['stop', 'prevent']) }, 'Click' ) } } ``` ## CamelCase Modifiers (No Helper Needed) For `capture`, `once`, and `passive` modifiers, use camelCase concatenation: ```javascript import { h } from 'vue' export default { setup() { const handler = () => console.log('event!') return () => h('div', { // @click.capture -> onClickCapture onClickCapture: handler, // @keyup.once -> onKeyupOnce onKeyupOnce: handler, // @scroll.passive -> onScrollPassive onScrollPassive: handler, // @mouseover.once.capture -> onMouseoverOnceCapture onMouseoverOnceCapture: handler }) } } ``` ## withModifiers Examples ```javascript import { h, withModifiers } from 'vue' export default { setup() { const handleClick = () => console.log('clicked') const handleSubmit = () => console.log('submitted') return () => h('div', [ // .stop modifier h('button', { onClick: withModifiers(handleClick, ['stop']) }, 'Stop Propagation'), // .prevent modifier h('form', { onSubmit: withModifiers(handleSubmit, ['prevent']) }, [ h('button', { type: 'submit' }, 'Submit') ]), // .self modifier - only trigger if event.target is the element itself h('div', { onClick: withModifiers(handleClick, ['self']), style: { padding: '20px', background: '#eee' } }, [ h('button', 'Click me (won\'t trigger parent)') ]), // Multiple modifiers h('a', { href: '/path', onClick: withModifiers(handleClick, ['stop', 'prevent']) }, 'Link') ]) } } ``` ## Key Modifiers For keyboard events, use `withKeys` for key modifiers: ```javascript import { h, withKeys } from 'vue' export default { setup() { const handleEnter = () => console.log('Enter pressed') const handleEscape = () => console.log('Escape pressed') return () => h('input', { // @keyup.enter onKeyup: withKeys(handleEnter, ['enter']), // Multiple keys onKeydown: withKeys(handleEscape, ['escape', 'esc']) }) } } ``` ## JSX Equivalent ```jsx import { withModifiers, withKeys } from 'vue' export default { setup() { const handleClick = () => console.log('clicked') return () => (