Skip to content

bug: [vue-output-target] Symbol() appearing in aria-label attributes #762

@alexkaduk

Description

@alexkaduk

Prerequisites

Framework Output Target

Vue (@stencil/vue-output-target)

Output Target Version

0.12.0

Stencil Version

4.37.1

Reproduction URL

https://stackblitz.com/edit/fp1e3uzz?file=index.html

Describe the Bug

The @stencil/vue-output-target runtime renders aria-label="Symbol()" in the DOM for components that don't explicitly set ARIA properties, causing Playwright accessibility tests to fail and creating invalid ARIA attributes.

Environment

  • Stencil Core: 4.37.1
  • Vue Output Target: 0.12.2 (specified as ^0.12.0)
  • Vue: 3.4.34
  • Node: 22.19.0
  • TypeScript: 5.8.3

Reproduction

Minimal Example

  1. Stencil component with optional ARIA prop:
@Component({ tag: 'my-button' })
export class MyButton {
  @Prop() ariaLabel?: string;
  
  render() {
    return <button>Click me</button>;
  }
}
  1. Vue wrapper generated by vue-output-target:
// stencil.config.ts
import { vueOutputTarget } from '@stencil/vue-output-target';

export const config: Config = {
  outputTargets: [
    vueOutputTarget({
      componentCorePackage: 'my-components',
      proxiesFile: '../vue-lib/src/components.ts',
    }),
  ],
};
  1. Use component in Vue without setting aria-label:
<template>
  <MyButton>Click me</MyButton>
</template>
  1. Rendered output:
<!-- Expected: -->
<my-button>Click me</my-button>

<!-- Actual: -->
<my-button aria-label="Symbol()">Click me</my-button>

Visual Evidence

Chrome DevTools Accessibility Tree:

RootWebArea "VueTestApp" focusable: true
  └─ main ""
      ├─ button "Symbol()" focusable: true          ❌ BUG
      └─ button "Symbol()" disabled: true           ❌ BUG

Root Cause

File: packages/vue-output-target/dist/runtime.js (line ~277)

The bug is in the prop handling logic where ARIA properties are added without checking if the value is EMPTY_PROP (a Symbol used as placeholder):

// BUGGY CODE
for (const key in props) {
    const value = props[key];
    if ((props.hasOwnProperty(key) && value !== EMPTY_PROP) || key.startsWith(ARIA_PROP_PREFIX)) {
        propsToAdd[key] = value;  // ❌ Bug: Adds Symbol for ARIA props
    }
    // ...
}

Expected Behavior

ARIA properties with EMPTY_PROP (Symbol) values should be filtered out and not added to the DOM.

Actual Behavior

<my-button aria-label="Symbol()">Button</my-button>

Additional Context

We maintain a large component library (Siemens iX) with Vue wrappers generated by this output target. All our Vue Playwright accessibility tests are currently failing due to this bug, while React and Angular tests pass with identical components.


Steps to Reproduce

  1. Open the app and run it https://stackblitz.com/edit/fp1e3uzz?file=index.html
  2. It should be possible to open it in separate tab (url should be https://fp1e3uzz-4sfd--5173--508a1324.local-credentialless.webcontainer.io/ )
  3. Open chrome inspector
  4. Switch to accessibility tree view with
Image 5. Symbol() attribute for the button should be there, it is bug Image

Actual Behavior

When no ARIA attribute is set:

<!-- ❌ Bug: Symbol() appears in the DOM -->
<my-button aria-label="Symbol()">Button</my-button>

When ARIA attribute IS set:

<!-- ✅ Works correctly -->
<my-button aria-label="Close">×</my-button>

Expected Behavior

When no ARIA attribute is set:

<!-- No aria-label attribute in the DOM -->
<my-button>Button</my-button>

When ARIA attribute IS set:

<MyButton aria-label="Close">×</MyButton>
<!-- Renders the actual value -->
<my-button aria-label="Close">×</my-button>

Additional Context

No response

Logs


Metadata

Metadata

Assignees

No one assigned

    Labels

    help wanteda good issue for the community

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions