--- 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 () => (
Child content
{}, ['enter'])} />
); }, }; ``` ## Reference - [Vue.js Render Functions - Event Modifiers](https://vuejs.org/guide/extras/render-function.html#event-modifiers)