Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/renderless/src/dropdown/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export const initAria =
({ state, props }: Pick<IDropdownRenderlessParams, 'state' | 'props'>) =>
() => {
state.dropdownElm?.setAttribute('id', state.listId)
state.triggerElm?.setAttribute('aria-haspopup', 'list')
state.triggerElm?.setAttribute('aria-haspopup', 'menu')
state.triggerElm?.setAttribute('aria-controls', state.listId)

if (!props.splitButton || !props.singleButton) {
Expand Down
1 change: 1 addition & 0 deletions packages/vue/src/dropdown-item/src/pc.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
@mousedown.stop
:aria-disabled="disabled"
:tabindex="disabled ? null : -1"
role="menuitem"
>
<div class="tiny-dropdown-item__wrap">
<span
Expand Down
1 change: 1 addition & 0 deletions packages/vue/src/dropdown-menu/src/pc.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
v-show="state.showPopper"
@mouseenter="handleMouseenter"
@mouseleave="handleMouseleave"
role="menu"
>
<template v-if="state.initShowPopper || state.showPopper">
<slot :selected-index="state.selectedIndex">
Expand Down
12 changes: 8 additions & 4 deletions packages/vue/src/dropdown/src/pc.vue
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export default defineComponent({
class={`tiny-dropdown__caret-button ${triggerClass}`}
disabled={disabled}
reset-time={0}>
<ButtonIconDown class={visibleClass}></ButtonIconDown>
<ButtonIconDown class={visibleClass} aria-label="down"></ButtonIconDown>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace generic aria-label="down" with descriptive, internationalized labels.

The aria-label="down" additions describe the icon's visual direction rather than the element's purpose. For accessibility:

  1. Use action-oriented labels: Screen reader users need to understand what the element does, not what it looks like. Consider "Open menu", "Toggle dropdown", or similar.

  2. Internationalize the labels: The hardcoded English string conflicts with the i18n TODO comment (line 93). Use a translatable string or prop.

  3. Apply to interactive elements only: Decorative icons should be aria-hidden="true", with the aria-label on the containing button/trigger instead.

🔎 Suggested approach

For split button (line 155):

-<ButtonIconDown class={visibleClass} aria-label="down"></ButtonIconDown>
+<ButtonIconDown class={visibleClass} aria-hidden="true"></ButtonIconDown>

And add aria-label to the button itself:

 <tiny-button
   ref="trigger"
   type={type}
   size={size}
   class={`tiny-dropdown__caret-button ${triggerClass}`}
   disabled={disabled}
-  reset-time={0}>
+  reset-time={0}
+  aria-label={t('ui.dropdown.toggleMenu')}>

Similar patterns apply to the other locations (lines 173, 200, 209). Consider adding an ariaLabel prop to allow customization while providing a sensible default.

Also applies to: 172-174, 199-200, 208-209

🤖 Prompt for AI Agents
packages/vue/src/dropdown/src/pc.vue around line 155 (and similarly lines
172-174, 199-200, 208-209): the ButtonIconDown currently uses aria-label="down"
which describes appearance not action and is hardcoded English; change so the
icon itself is decorative (add aria-hidden="true" and remove aria-label) and
move a descriptive, action-oriented, translatable aria-label onto the
interactive button/trigger (e.g., "Open menu" or "Toggle dropdown") by adding an
ariaLabel prop with a sensible i18n default and using that prop on the button;
apply the same pattern to the other listed locations so all interactive controls
use an i18n-aware ariaLabel prop and icons are aria-hidden.

</tiny-button>
</tiny-button-group>
)
Expand All @@ -169,7 +169,9 @@ export default defineComponent({

// 增加一层,vue3 环境中无法使用 slots.default 的方式获取原生 DOM 元素
const suffixInner = showIcon ? (
<span class={'tiny-dropdown__suffix-inner ' + visibleClass}>{suffixSlot || <IconDown></IconDown>}</span>
<span class={'tiny-dropdown__suffix-inner ' + visibleClass}>
{suffixSlot || <IconDown aria-label="down"></IconDown>}
</span>
) : (
''
)
Expand All @@ -194,15 +196,17 @@ export default defineComponent({
class={`tiny-dropdown__border ${state.visible ? 'is-expand' : ''}${
showIcon ? ' is-show-icon ' : ''
} ${triggerClass}`}
reset-time={0}>
reset-time={0}
aria-label="down">
{prefixInner}
{defaultTriggerElm}
{suffixInner}
</tiny-button>
) : (
<span
ref="trigger"
class={`is-text${state.visible ? ' is-expand' : ' is-hide'}${disabled ? ' is-disabled' : ''} ${triggerClass}`}>
class={`is-text${state.visible ? ' is-expand' : ' is-hide'}${disabled ? ' is-disabled' : ''} ${triggerClass}`}
aria-label="down">
{prefixInner}
{defaultTriggerElm}
{suffixInner}
Expand Down
Loading