Files
agent-skills/skills/vue-best-practices/reference/render-function-event-modifiers.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

4.6 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Use withModifiers for Event Modifiers in Render Functions MEDIUM Manual modifier implementation is error-prone; use withModifiers helper best-practice
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:

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')
  }
}
// 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:

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:

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

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:

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

import { withModifiers, withKeys } from 'vue'

export default {
  setup() {
    const handleClick = () => console.log('clicked')

    return () => (
      <div>
        <button onClick={withModifiers(handleClick, ['stop'])}>
          Stop
        </button>

        <div onClick={withModifiers(handleClick, ['self'])}>
          <span>Child content</span>
        </div>

        <input onKeyup={withKeys(() => {}, ['enter'])} />
      </div>
    )
  }
}

Reference