Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/click-events-on-components.md
1---2title: Click Events on Custom Components Require Emit or Fallthrough3impact: HIGH4impactDescription: Native click events on custom components won't work without proper emit declaration or attribute fallthrough5type: gotcha6tags: [vue3, events, components, emit, click, migration]7---89# Click Events on Custom Components Require Emit or Fallthrough1011**Impact: HIGH** - Unlike native HTML elements, custom Vue components don't automatically forward native DOM events like `click`. You must either emit the event explicitly, rely on attribute fallthrough to a single root element, or use the `.native` modifier (Vue 2 only, removed in Vue 3). This is a common source of confusion and migration issues.1213## Task Checklist1415- [ ] Declare emitted events using `defineEmits` in child components16- [ ] Emit click events from child component when needed17- [ ] Understand that single-root components automatically forward attrs to root18- [ ] Remove `.native` modifier when migrating from Vue 2 to Vue 319- [ ] For multi-root components, explicitly bind `$attrs` or emit events2021**Incorrect:**22```html23<!-- WRONG: Expecting native click to work on custom component -->24<template>25<MyButton @click="handleClick">Click me</MyButton>26<!-- This may not work as expected! -->27</template>28```2930```html31<!-- WRONG: Vue 2 .native modifier doesn't exist in Vue 3 -->32<template>33<MyButton @click.native="handleClick">Click me</MyButton>34<!-- Error in Vue 3: .native modifier removed -->35</template>36```3738```html39<!-- WRONG: Multi-root component with no attr binding -->40<!-- MyButton.vue -->41<template>42<span>Icon</span>43<button>{{ label }}</button>44<!-- No root element to receive click! -->45</template>46```4748**Correct:**49```html50<!-- CORRECT: Child component emits the click event -->51<!-- MyButton.vue -->52<template>53<button @click="$emit('click', $event)">54<slot></slot>55</button>56</template>5758<script setup>59defineEmits(['click'])60</script>6162<!-- Parent.vue -->63<template>64<MyButton @click="handleClick">Click me</MyButton>65</template>66```6768```html69<!-- CORRECT: Single root element with automatic fallthrough -->70<!-- MyButton.vue -->71<template>72<button>73<slot></slot>74</button>75<!-- @click from parent automatically falls through to button -->76</template>7778<!-- Parent.vue -->79<template>80<MyButton @click="handleClick">Click me</MyButton>81</template>82```8384```html85<!-- CORRECT: Multi-root component with explicit $attrs binding -->86<!-- MyButton.vue -->87<template>88<span>Icon</span>89<button v-bind="$attrs">90<slot></slot>91</button>92</template>9394<script setup>95defineOptions({96inheritAttrs: false97})98</script>99```100101## Component Events Don't Bubble102103```javascript104// Important: Component-emitted events do NOT bubble105// You can only listen to events from direct children106107// WRONG: Trying to catch grandchild events108<GrandParent @child-event="handle"> <!-- Won't receive! -->109<Parent>110<Child @click="$emit('child-event')" />111</Parent>112</GrandParent>113114// CORRECT: Each level must relay the event115<GrandParent @child-event="handle">116<Parent @child-event="$emit('child-event', $event)">117<Child @click="$emit('child-event')" />118</Parent>119</GrandParent>120```121122## Vue 3 Native Event Behavior123124```javascript125// In Vue 3, if you declare an event in emits:126defineEmits(['click'])127128// Then @click on the component ONLY listens to emitted events129// NOT native click events130131// If you don't declare 'click' in emits:132defineEmits(['custom-event'])133134// Then @click on single-root component will:135// 1. Fall through to root element as native listener136// 2. Fire on native click137```138139## Composition API Emit Pattern140141```vue142<script setup>143// Define what events this component emits144const emit = defineEmits(['click', 'update', 'delete'])145146function handleClick(event) {147// Do component logic148processClick()149150// Then emit to parent151emit('click', event)152}153</script>154155<template>156<button @click="handleClick">157<slot></slot>158</button>159</template>160```161162## Migration from Vue 2163164```html165<!-- Vue 2: Used .native for native events on components -->166<MyComponent @click.native="handleClick" />167168<!-- Vue 3: Remove .native, ensure component handles the event -->169<MyComponent @click="handleClick" />170171<!-- Make sure MyComponent either:1721. Has single root that receives fallthrough attrs1732. Explicitly emits 'click' event1743. Uses v-bind="$attrs" on intended element -->175```176177## Reference178- [Vue.js Component Events](https://vuejs.org/guide/components/events.html)179- [Vue.js Fallthrough Attributes](https://vuejs.org/guide/components/attrs.html)180- [Vue 3 Migration - .native Modifier Removed](https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html)181