Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
5 changes: 5 additions & 0 deletions .changeset/dropdown-button-decorative-icon.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siemens/ix': patch
---

Fix `ix-dropdown-button` accessibility by hiding decorative content and exposing only the host as the interactive, named menu button.
Comment thread
dmytro-halimov marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.dropdown-button {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
position: relative;
max-width: 20rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,27 @@ import {
imports: [IxDropdownButton, IxDropdownItem],
template: `
<div class="example">
<ix-dropdown-button label="Dropdown" icon="checkboxes">
<ix-dropdown-button label="Primary dropdown" icon="checkboxes">
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button variant="subtle-primary" label="Dropdown" icon="checkboxes">
<ix-dropdown-button
variant="subtle-primary"
label="Subtle primary dropdown"
icon="checkboxes"
>
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button variant="tertiary" label="Dropdown" icon="checkboxes">
<ix-dropdown-button
variant="tertiary"
label="Tertiary dropdown"
icon="checkboxes"
>
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button label="Dropdown" disabled icon="checkboxes">
<ix-dropdown-button label="Disabled dropdown" disabled icon="checkboxes">
Comment thread
dmytro-halimov marked this conversation as resolved.
</ix-dropdown-button>
</div>
`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.dropdown-button {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
position: relative;
max-width: 20rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,27 @@ import { Component } from '@angular/core';
selector: 'app-example',
template: `
<div class="example">
<ix-dropdown-button label="Dropdown" icon="checkboxes">
<ix-dropdown-button label="Primary dropdown" icon="checkboxes">
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button variant="subtle-primary" label="Dropdown" icon="checkboxes">
<ix-dropdown-button
variant="subtle-primary"
label="Subtle primary dropdown"
icon="checkboxes"
>
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button variant="tertiary" label="Dropdown" icon="checkboxes">
<ix-dropdown-button
variant="tertiary"
label="Tertiary dropdown"
icon="checkboxes"
>
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button label="Dropdown" disabled icon="checkboxes">
<ix-dropdown-button label="Disabled dropdown" disabled icon="checkboxes">
</ix-dropdown-button>
</div>
`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,34 @@
@use 'misc/common-variables' as vars;
@use 'mixins/shadow-dom/component';

@mixin button-state($state) {
$variants: (
primary,
secondary,
tertiary,
subtle-primary,
subtle-secondary,
subtle-tertiary,
danger-primary,
danger-secondary,
danger-tertiary
);

@each $variant in $variants {
.dropdown-button.#{$variant}:#{$state} {
--theme-btn-#{$variant}--border-color: var(
--theme-btn-#{$variant}--border-color--#{$state}
);
--theme-btn-#{$variant}--background: var(
--theme-btn-#{$variant}--background--#{$state}
);
--theme-btn-#{$variant}--color: var(
--theme-btn-#{$variant}--color--#{$state}
);
}
}
}

@mixin triangle($name: '') {
@if ($name != '') {
$name: '#{$name}-';
Expand Down Expand Up @@ -70,8 +98,12 @@
position: relative;
width: 100%;
height: 100%;
cursor: pointer;
}

@include button-state('hover');
@include button-state('active');

.dropdown-button > ix-button {
width: 100%;
height: 100%;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ export class DropdownButton
@State() dropdownShow = false;

private inheritAriaAttributes: A11yAttributes = {};
private hostAriaLabel?: string;
private renderedAriaLabel?: string;

private dropdownButtonId = this.getHostElementId();

Expand Down Expand Up @@ -180,6 +182,12 @@ export class DropdownButton
}

override componentWillRender(): Promise<void> | void {
const hostAriaLabel =
this.hostElement.getAttribute('aria-label') ?? undefined;
if (hostAriaLabel !== this.renderedAriaLabel) {
this.hostAriaLabel = hostAriaLabel;
}

this.hostContext = {
breadcrumb: !!closestPassShadow(this.hostElement, 'ix-breadcrumb'),
datePicker: !!closestPassShadow(this.hostElement, 'ix-date-picker'),
Expand Down Expand Up @@ -210,8 +218,16 @@ export class DropdownButton
}

override render() {
const ariaLabel =
this.hostAriaLabel ??
this.ariaLabelDropdownButton ??
this.label ??
(this.dropdownShow ? 'Close dropdown' : 'Open dropdown');
Comment thread
dmytro-halimov marked this conversation as resolved.
Outdated
this.renderedAriaLabel = ariaLabel;

const ariaAttributes = {
...this.inheritAriaAttributes,
'aria-label': ariaLabel,
Comment thread
dmytro-halimov marked this conversation as resolved.
'aria-haspopup': 'true',
'aria-disabled': a11yBoolean(this.disabled),
'aria-expanded': a11yBoolean(this.dropdownShow),
Expand Down Expand Up @@ -247,12 +263,18 @@ export class DropdownButton
tabIndex={this.disabled ? -1 : 0}
{...ariaAttributes}
>
<div class="dropdown-button">
<div
class={{
'dropdown-button': true,
[this.variant]: true,
}}
>
{this.label || this.label === null ? (
<ix-button
{...commonProperties}
class={'internal-button'}
alignment="start"
inert={true}
ref={(ref) => forceTabIndex(ref, -1)}
ariaLabelButton={
this.ariaLabelDropdownButton ??
Expand All @@ -262,6 +284,7 @@ export class DropdownButton
<div class={'content'}>
{this.icon ? (
<ix-icon
aria-hidden="true"
name={this.icon}
size="24"
class={'dropdown-icon'}
Expand All @@ -287,6 +310,7 @@ export class DropdownButton
<ix-icon-button
{...commonProperties}
icon={this.icon}
inert={true}
ref={(ref) => forceTabIndex(ref, -1)}
aria-label={
this.ariaLabelDropdownButton ??
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.dropdown-button {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
position: relative;
max-width: 20rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,27 @@
</head>
<body>
<div class="dropdown-button">
<ix-dropdown-button label="Dropdown" icon="checkboxes">
<ix-dropdown-button label="Primary dropdown" icon="checkboxes">
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button variant="subtle-primary" label="Dropdown" icon="checkboxes">
<ix-dropdown-button
variant="subtle-primary"
label="Subtle primary dropdown"
icon="checkboxes"
>
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button variant="tertiary" label="Dropdown" icon="checkboxes">
<ix-dropdown-button
variant="tertiary"
label="Tertiary dropdown"
icon="checkboxes"
>
<ix-dropdown-item label="Item 1"></ix-dropdown-item>
<ix-dropdown-item label="Item 2"></ix-dropdown-item>
</ix-dropdown-button>
<ix-dropdown-button label="Dropdown" disabled icon="checkboxes">
<ix-dropdown-button label="Disabled dropdown" disabled icon="checkboxes">
</ix-dropdown-button>
</div>
<script type="module" src="./init.js"></script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.dropdown-button {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
position: relative;
max-width: 20rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,28 @@ import { IxDropdownButton, IxDropdownItem } from '@siemens/ix-react';
export default () => {
return (
<div className="dropdown-button">
<IxDropdownButton label="Dropdown" icon={iconCheckboxes}>
<IxDropdownButton label="Primary dropdown" icon={iconCheckboxes}>
<IxDropdownItem label="Item 1"></IxDropdownItem>
<IxDropdownItem label="Item 2"></IxDropdownItem>
</IxDropdownButton>
<IxDropdownButton variant="subtle-primary" label="Dropdown" icon={iconCheckboxes}>
<IxDropdownButton
variant="subtle-primary"
label="Subtle primary dropdown"
icon={iconCheckboxes}
>
<IxDropdownItem label="Item 1"></IxDropdownItem>
<IxDropdownItem label="Item 2"></IxDropdownItem>
</IxDropdownButton>
<IxDropdownButton variant="tertiary" label="Dropdown" icon={iconCheckboxes}>
<IxDropdownButton
variant="tertiary"
label="Tertiary dropdown"
icon={iconCheckboxes}
>
<IxDropdownItem label="Item 1"></IxDropdownItem>
<IxDropdownItem label="Item 2"></IxDropdownItem>
</IxDropdownButton>
<IxDropdownButton
label="Dropdown"
label="Disabled dropdown"
disabled
icon={iconCheckboxes}
></IxDropdownButton>
Expand Down
21 changes: 21 additions & 0 deletions packages/storybook-docs/src/stories/dropdown-button.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,27 @@ export const Primary: Story = {
},
};

export const WithDropdownItems: Story = {
args: {
label: 'Button',
variant: 'primary',
},
render: (args) => {
const container = genericRender('ix-dropdown-button', args);
const dropdownButton = container.querySelector('ix-dropdown-button')!;

['Dropdown Item 1', 'Dropdown Item 2', 'Dropdown Item 3'].forEach(
(label) => {
const dropdownItem = document.createElement('ix-dropdown-item');
dropdownItem.label = label;
dropdownButton.appendChild(dropdownItem);
}
);
Comment thread
dmytro-halimov marked this conversation as resolved.
Outdated

return container;
},
};

export const Secondary: Story = {
args: {
label: 'Button',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
.dropdown-button {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
position: relative;
max-width: 20rem;
Expand Down
16 changes: 12 additions & 4 deletions packages/vue-test-app/src/preview-examples/dropdown-button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,27 @@ import { IxDropdownButton } from '@siemens/ix-vue';

<template>
<div class="dropdown-button">
<IxDropdownButton label="Dropdown" :icon="iconCheckboxes">
<IxDropdownButton label="Primary dropdown" :icon="iconCheckboxes">
<IxDropdownItem label="Item 1"></IxDropdownItem>
<IxDropdownItem label="Item 2"></IxDropdownItem>
</IxDropdownButton>
<IxDropdownButton variant="subtle-primary" label="Dropdown" :icon="iconCheckboxes">
<IxDropdownButton
variant="subtle-primary"
label="Subtle primary dropdown"
:icon="iconCheckboxes"
>
<IxDropdownItem label="Item 1"></IxDropdownItem>
<IxDropdownItem label="Item 2"></IxDropdownItem>
</IxDropdownButton>
<IxDropdownButton variant="tertiary" label="Dropdown" :icon="iconCheckboxes">
<IxDropdownButton
variant="tertiary"
label="Tertiary dropdown"
:icon="iconCheckboxes"
>
<IxDropdownItem label="Item 1"></IxDropdownItem>
<IxDropdownItem label="Item 2"></IxDropdownItem>
</IxDropdownButton>
<IxDropdownButton label="Dropdown" disabled :icon="iconCheckboxes">
<IxDropdownButton label="Disabled dropdown" disabled :icon="iconCheckboxes">
Comment thread
dmytro-halimov marked this conversation as resolved.
Outdated
<IxDropdownItem label="Item 1"></IxDropdownItem>
<IxDropdownItem label="Item 2"></IxDropdownItem>
</IxDropdownButton>
Expand Down
Loading