diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index df438d47eee..7e0bceb6f21 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -471,6 +471,14 @@ describe('defineCustomElement', () => { container.appendChild(e) expect(e.shadowRoot!.innerHTML).toBe('
') }) + + // #12408 + test('should set number tabindex as attribute', () => { + render(h('my-el-attrs', { tabindex: 1, 'data-test': true }), container) + const el = container.children[0] as HTMLElement + expect(el.getAttribute('tabindex')).toBe('1') + expect(el.getAttribute('data-test')).toBe('true') + }) }) describe('emits', () => { diff --git a/packages/runtime-dom/src/patchProp.ts b/packages/runtime-dom/src/patchProp.ts index b6af8997112..70f7128c871 100644 --- a/packages/runtime-dom/src/patchProp.ts +++ b/packages/runtime-dom/src/patchProp.ts @@ -60,7 +60,11 @@ export const patchProp: DOMRendererOptions['patchProp'] = ( } else if ( // #11081 force set props for possible async custom element (el as VueElement)._isVueCE && - (/[A-Z]/.test(key) || !isString(nextValue)) + // #12408 check if it's hyphen prop or it's async custom element + (camelize(key) in el || + // @ts-expect-error _def is private + ((el as VueElement)._def.__asyncLoader && + (/[A-Z]/.test(key) || !isString(nextValue)))) ) { patchDOMProp(el, camelize(key), nextValue, parentComponent, key) } else {