From 030afc7bc935a84cc57595688b50cce900da9ed3 Mon Sep 17 00:00:00 2001
From: xiaocainiao633 <1770329881@qq.com>
Date: Tue, 21 Oct 2025 21:24:00 +0800
Subject: [PATCH] fix(components): [input-tag] keyboard handling should occur
on keydown (#22486)
* fix(components): issue of enter event bubbling in input-tag component
* fix(components): fix test
* fix(components): resolve new problem
* fix(components): fix input-tag-new
* fix(components): fix input-tag-new
* fix(components): resolve new problem
---
.../input-tag/__tests__/input-tag.test.tsx | 30 ++++++++++---------
.../src/composables/use-input-tag.ts | 17 +++++++++++
.../components/input-tag/src/input-tag.vue | 4 ++-
3 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/packages/components/input-tag/__tests__/input-tag.test.tsx b/packages/components/input-tag/__tests__/input-tag.test.tsx
index dd2950867e..87f98fe210 100644
--- a/packages/components/input-tag/__tests__/input-tag.test.tsx
+++ b/packages/components/input-tag/__tests__/input-tag.test.tsx
@@ -30,18 +30,20 @@ describe('InputTag.vue', () => {
const wrapper = mount(() => )
await wrapper.find('input').setValue(AXIOM)
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.enter })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.enter })
expect(wrapper.findAll('.el-tag').length).toBe(1)
expect(wrapper.find('.el-tag').text()).toBe(AXIOM)
expect(inputValue.value).toEqual([AXIOM])
await wrapper.find('input').setValue('--')
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.enter })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.enter })
expect(wrapper.findAll('.el-tag').length).toBe(2)
expect(wrapper.findAll('.el-tag')[1].text()).toBe('--')
expect(inputValue.value).toEqual([AXIOM, '--'])
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.backspace })
+ await wrapper
+ .find('input')
+ .trigger('keydown', { code: EVENT_CODE.backspace })
expect(wrapper.findAll('.el-tag').length).toBe(1)
expect(wrapper.find('.el-tag').text()).toBe(AXIOM)
expect(inputValue.value).toEqual([AXIOM])
@@ -57,10 +59,10 @@ describe('InputTag.vue', () => {
))
await wrapper.find('input').setValue(AXIOM)
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.enter })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.enter })
expect(wrapper.findAll('.el-tag').length).toBe(0)
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.space })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.space })
expect(wrapper.findAll('.el-tag').length).toBe(1)
expect(wrapper.find('.el-tag').text()).toBe(AXIOM)
})
@@ -72,7 +74,7 @@ describe('InputTag.vue', () => {
expect(wrapper.findAll('.el-tag').length).toBe(1)
await wrapper.find('input').setValue(AXIOM)
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.enter })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.enter })
expect(wrapper.findAll('.el-tag').length).toBe(1)
})
@@ -134,7 +136,7 @@ describe('InputTag.vue', () => {
)
await wrapper.find('input').setValue('Rem')
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.enter })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.enter })
expect(wrapper.find('input').element.placeholder).toMatchInlineSnapshot(
`""`
)
@@ -312,13 +314,13 @@ describe('InputTag.vue', () => {
))
await wrapper.find('input').setValue(AXIOM)
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.enter })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.enter })
expect(handleModelValue).toHaveBeenCalledOnce()
expect(handleModelValue).toHaveBeenCalledWith([AXIOM])
await wrapper
.find('input')
- .trigger('keyup', { code: EVENT_CODE.backspace })
+ .trigger('keydown', { code: EVENT_CODE.backspace })
expect(handleModelValue).toHaveBeenCalledTimes(2)
expect(handleModelValue).toHaveBeenCalledWith([])
})
@@ -331,13 +333,13 @@ describe('InputTag.vue', () => {
))
await wrapper.find('input').setValue(AXIOM)
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.enter })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.enter })
expect(handleChange).toHaveBeenCalledOnce()
expect(handleChange).toHaveBeenCalledWith([AXIOM])
await wrapper
.find('input')
- .trigger('keyup', { code: EVENT_CODE.backspace })
+ .trigger('keydown', { code: EVENT_CODE.backspace })
expect(handleChange).toHaveBeenCalledTimes(2)
expect(handleChange).toHaveBeenCalledWith([])
})
@@ -359,7 +361,7 @@ describe('InputTag.vue', () => {
))
await wrapper.find('input').setValue(AXIOM)
- await wrapper.find('input').trigger('keyup', { code: EVENT_CODE.enter })
+ await wrapper.find('input').trigger('keydown', { code: EVENT_CODE.enter })
expect(handleTagAdd).toHaveBeenCalledOnce()
expect(handleTagAdd).toHaveBeenCalledWith(AXIOM)
})
@@ -378,14 +380,14 @@ describe('InputTag.vue', () => {
await wrapper
.find('input')
- .trigger('keyup', { code: EVENT_CODE.backspace })
+ .trigger('keydown', { code: EVENT_CODE.backspace })
expect(handleTagRemove).toHaveBeenCalledTimes(2)
expect(handleTagRemove).toHaveBeenNthCalledWith(2, AXIOM, 0)
expect(inputValue.value).toEqual([])
await wrapper
.find('input')
- .trigger('keyup', { code: EVENT_CODE.backspace })
+ .trigger('keydown', { code: EVENT_CODE.backspace })
expect(handleTagRemove).toHaveBeenCalledTimes(2)
})
diff --git a/packages/components/input-tag/src/composables/use-input-tag.ts b/packages/components/input-tag/src/composables/use-input-tag.ts
index 87527b3810..dcc93e4a30 100644
--- a/packages/components/input-tag/src/composables/use-input-tag.ts
+++ b/packages/components/input-tag/src/composables/use-input-tag.ts
@@ -9,6 +9,7 @@ import {
debugWarn,
ensureArray,
getEventCode,
+ isAndroid,
isUndefined,
} from '@element-plus/utils'
import { useComposition, useFocusController } from '@element-plus/hooks'
@@ -119,6 +120,21 @@ export function useInputTag({ props, emit, formItem }: UseInputTagOptions) {
}
}
+ const handleKeyup = (event: KeyboardEvent) => {
+ if (isComposing.value || !isAndroid()) return
+ const code = getEventCode(event)
+
+ switch (code) {
+ case EVENT_CODE.space:
+ if (props.trigger === EVENT_CODE.space) {
+ event.preventDefault()
+ event.stopPropagation()
+ handleAddTag()
+ }
+ break
+ }
+ }
+
const handleAddTag = () => {
const value = inputValue.value?.trim()
if (!value || inputLimit.value) return
@@ -221,6 +237,7 @@ export function useInputTag({ props, emit, formItem }: UseInputTagOptions) {
handleDragged,
handleInput,
handleKeydown,
+ handleKeyup,
handleAddTag,
handleRemoveTag,
handleClear,
diff --git a/packages/components/input-tag/src/input-tag.vue b/packages/components/input-tag/src/input-tag.vue
index be2830f3c4..cb7f0dae69 100644
--- a/packages/components/input-tag/src/input-tag.vue
+++ b/packages/components/input-tag/src/input-tag.vue
@@ -89,7 +89,8 @@
@compositionupdate="handleCompositionUpdate"
@compositionend="handleCompositionEnd"
@input="handleInput"
- @keyup="handleKeydown"
+ @keydown="handleKeydown"
+ @keyup="handleKeyup"
/>