Skip to content

Commit

Permalink
Dropdown a11y updates (#3586)
Browse files Browse the repository at this point in the history
  • Loading branch information
Elizabeth Judd authored and asudoh committed Aug 5, 2019
1 parent 9d3ab68 commit 3f183ff
Show file tree
Hide file tree
Showing 5 changed files with 475 additions and 131 deletions.
26 changes: 20 additions & 6 deletions packages/components/src/components/dropdown/_dropdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@
transform-origin: 50% 45%;
}

button.#{$prefix}--dropdown-text {
// button-reset mixin contradicts with bx--dropdown-text styles
background: none;
border: none;
width: 100%;
text-align: left;

&:focus {
@include focus-outline('outline');
}
}

.#{$prefix}--dropdown-text {
@include type-style('body-short-01');
display: block;
Expand All @@ -137,6 +149,7 @@

.#{$prefix}--dropdown-list {
@include reset;
@include focus-outline('reset');
@include layer('overlay');
@include type-style('body-short-01');
background-color: $ui-01;
Expand Down Expand Up @@ -200,18 +213,19 @@
overflow: hidden;
white-space: nowrap;

&:focus {
@include focus-outline('outline');
margin: 0;
padding: rem(11px) rem(16px);
}

&:hover {
color: $text-01;
border-color: transparent;
}
}

.#{$prefix}--dropdown--focused,
.#{$prefix}--dropdown-link:focus {
@include focus-outline('outline');
margin: 0;
padding: rem(11px) rem(16px);
}

.#{$prefix}--dropdown-item:hover .#{$prefix}--dropdown-link {
border-bottom-color: $hover-ui;
}
Expand Down
20 changes: 20 additions & 0 deletions packages/components/src/components/dropdown/dropdown.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ const items = [
module.exports = {
context: {
prefix,
default: {
idSuffix: `example-${Math.random()
.toString(36)
.substr(2)}`,
},
helper: {
idSuffix: `example-${Math.random()
.toString(36)
.substr(2)}`,
},
disabled: {
idSuffix: `example-${Math.random()
.toString(36)
.substr(2)}`,
},
invalid: {
idSuffix: `example-${Math.random()
.toString(36)
.substr(2)}`,
},
},
variants: [
{
Expand Down
188 changes: 79 additions & 109 deletions packages/components/src/components/dropdown/dropdown.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,150 +4,120 @@
This source code is licensed under the Apache-2.0 license found in the
LICENSE file in the root directory of this source tree.
-->

<div class="{{@root.prefix}}--form-item">
<div class="{{@root.prefix}}--dropdown__wrapper {{#if inline}}{{@root.prefix}}--dropdown__wrapper--inline{{/if}}">
<label for="dropdown-id" class="{{@root.prefix}}--label">Dropdown label</label>
<span id="{{default.idSuffix}}-label" class="{{@root.prefix}}--label">Dropdown label</span>
{{#unless inline}}
<div class="{{@root.prefix}}--form__helper-text">Optional helper text.</div>
{{/unless}}
<ul data-dropdown{{#if inline}} data-dropdown-type="inline" {{/if}} data-value id="dropdown-id"
class="{{@root.prefix}}--dropdown {{#if up}}{{@root.prefix}}--dropdown--up{{/if}} {{#if light}}{{@root.prefix}}--dropdown--light{{/if}} {{#if inline}}{{@root.prefix}}--dropdown--inline{{/if}}"
tabindex="0">
<li class="{{@root.prefix}}--dropdown-text">
{{#unless inline}} Dropdown option {{else}}
<span class="{{@root.prefix}}--dropdown-text__inner">Inline Dropdown label</span>
{{/unless}}
{{#unless inline}}
</li>
<li class="{{@root.prefix}}--dropdown__arrow-container">
{{/unless}}
{{ carbon-icon 'ChevronDown16' class=(add @root.prefix '--dropdown__arrow') }}
</li>
<li>
<ul class="{{@root.prefix}}--dropdown-list">
{{#each items}}
<li data-option data-value="{{value}}" class="{{@root.prefix}}--dropdown-item">
<a class="{{@root.prefix}}--dropdown-link" href="javascript:void(0)" tabindex="-1">{{label}}</a>
</li>
{{/each}}
</ul>
</li>
</ul>
<div data-dropdown{{#if inline}} data-dropdown-type="inline" {{/if}} data-value
class="{{@root.prefix}}--dropdown {{#if up}}{{@root.prefix}}--dropdown--up{{/if}} {{#if light}}{{@root.prefix}}--dropdown--light{{/if}} {{#if inline}}{{@root.prefix}}--dropdown--inline{{/if}}">
<button class="{{@root.prefix}}--dropdown-text" aria-haspopup="true" aria-expanded="false" aria-controls="{{default.idSuffix}}-menu" aria-labelledby="{{default.idSuffix}}-label {{default.idSuffix}}-value" type="button">
<span class="{{@root.prefix}}--dropdown-text__inner" id="{{default.idSuffix}}-value">{{#unless inline}} Dropdown option {{else}}Inline Dropdown label{{/unless}}</span>
<span class="{{@root.prefix}}--dropdown__arrow-container">
{{ carbon-icon 'ChevronDown16' class=(add @root.prefix '--dropdown__arrow') }}
</span>
</button>
<ul class="{{@root.prefix}}--dropdown-list" id="{{default.idSuffix}}-menu" role="menu" tabindex="0" id="{{default.idSuffix}}-menu" aria-hidden="true" wh-menu-anchor="left" aria-labelledby="{{default.idSuffix}}-label">
{{#each items as |item index|}}
<li data-option data-value="{{value}}" class="{{@root.prefix}}--dropdown-item">
<a class="{{@root.prefix}}--dropdown-link" href="javascript:void(0)" tabindex="-1" role="menuitemradio" aria-checked="{{#if index}}false{{else}}true{{/if}}" id="{{../default.idSuffix}}-item{{@index}}">{{label}}</a>
</li>
{{/each}}
</ul>
</div>
</div>
</div>

{{#unless inline}}
<div class="{{@root.prefix}}--form-item">
<div class="{{@root.prefix}}--dropdown__wrapper {{#if inline}}{{@root.prefix}}--dropdown__wrapper--inline{{/if}}">
<label for="dropdown-id-longer-helper-text" class="{{@root.prefix}}--label">Dropdown label</label>
<span id="{{helper.idSuffix}}-label" class="{{@root.prefix}}--label">Dropdown label</span>
<div class="{{@root.prefix}}--form__helper-text">Optional helper text here; if message is more than one line text
should wrap (~100 character count maximum)</div>
<ul data-dropdown{{#if inline}} data-dropdown-type="inline" {{/if}} data-value id="dropdown-id-longer-helper-text"
class="{{@root.prefix}}--dropdown {{#if up}}{{@root.prefix}}--dropdown--up{{/if}} {{#if light}}{{@root.prefix}}--dropdown--light{{/if}} {{#if inline}}{{@root.prefix}}--dropdown--inline{{/if}}"
tabindex="0">
<li class="{{@root.prefix}}--dropdown-text">
{{#unless inline}} Dropdown option {{else}}
<span class="{{@root.prefix}}--dropdown-text__inner">Inline Dropdown label</span>
{{/unless}}
{{#unless inline}}
</li>
<li class="{{@root.prefix}}--dropdown__arrow-container">
{{/unless}}
{{ carbon-icon 'ChevronDown16' class=(add @root.prefix '--dropdown__arrow') }}
</li>
<li>
<ul class="{{@root.prefix}}--dropdown-list">
{{#each items}}
<li data-option data-value="{{value}}" class="{{@root.prefix}}--dropdown-item">
<a class="{{@root.prefix}}--dropdown-link" href="javascript:void(0)" tabindex="-1">{{label}}</a>
</li>
{{/each}}
</ul>
</li>
</ul>
<div data-dropdown{{#if inline}} data-dropdown-type="inline" {{/if}} data-value
class="{{@root.prefix}}--dropdown {{#if up}}{{@root.prefix}}--dropdown--up{{/if}} {{#if light}}{{@root.prefix}}--dropdown--light{{/if}} {{#if inline}}{{@root.prefix}}--dropdown--inline{{/if}}">
<button class="{{@root.prefix}}--dropdown-text" aria-haspopup="true" aria-expanded="false" aria-controls="{{helper.idSuffix}}-menu" aria-labelledby="{{helper.idSuffix}}-label {{helper.idSuffix}}-value" type="button">
<span class="{{@root.prefix}}--dropdown-text__inner" id="{{helper.idSuffix}}-value">{{#unless inline}} Dropdown option {{else}}Inline Dropdown label{{/unless}}</span>
<span class="{{@root.prefix}}--dropdown__arrow-container">
{{ carbon-icon 'ChevronDown16' class=(add @root.prefix '--dropdown__arrow') }}
</span>
</button>
<ul class="{{@root.prefix}}--dropdown-list" role="menu" tabindex="0" id="{{helper.idSuffix}}-menu" aria-hidden="true" wh-menu-anchor="left" aria-labelledby="{{helper.idSuffix}}-label">
{{#each items as |item index|}}
<li data-option data-value="{{value}}" class="{{@root.prefix}}--dropdown-item">
<a class="{{@root.prefix}}--dropdown-link" href="javascript:void(0)" tabindex="-1" role="menuitemradio" aria-checked="{{#if index}}false{{else}}true{{/if}}" id="{{../helper.idSuffix}}-item{{@index}}">{{label}}</a>
</li>
{{/each}}
</ul>
</div>
</div>
</div>
{{/unless}}

<div class="{{@root.prefix}}--form-item">
<div class="{{@root.prefix}}--dropdown__wrapper {{#if inline}}{{@root.prefix}}--dropdown__wrapper--inline{{/if}}">
<label for="dropdown-id-disabled" class="{{@root.prefix}}--label {{@root.prefix}}--label--disabled">Dropdown
label</label>
<span id="{{disabled.idSuffix}}-label" class="{{@root.prefix}}--label {{@root.prefix}}--label--disabled" aria-disabled="true">Dropdown label</span>
{{#unless inline}}
<div class="{{@root.prefix}}--form__helper-text {{@root.prefix}}--form__helper-text--disabled">Optional helper text
<div class="{{@root.prefix}}--form__helper-text {{@root.prefix}}--form__helper-text--disabled" aria-disabled="true">Optional helper text
here; if message is more than one line text
should wrap (~100 character count maximum)</div>
{{/unless}}
<ul data-dropdown{{#if inline}} data-dropdown-type="inline" {{/if}} data-value id="dropdown-id-disabled"
class="{{@root.prefix}}--dropdown{{#if up}} {{@root.prefix}}--dropdown--up{{/if}}{{#if light}} {{@root.prefix}}--dropdown--light{{/if}}{{#if inline}} {{@root.prefix}}--dropdown--inline{{/if}} {{@root.prefix}}--dropdown--disabled"
tabindex="0">
<li class="{{@root.prefix}}--dropdown-text">
{{#unless inline}} Dropdown option {{else}}
<span class="{{@root.prefix}}--dropdown-text__inner">Inline Dropdown label</span>
{{/unless}}
{{#unless inline}}
</li>
<li class="{{@root.prefix}}--dropdown__arrow-container">
{{/unless}}
{{ carbon-icon 'ChevronDown16' class=(add @root.prefix '--dropdown__arrow') }}
</li>
<li>
<ul class="{{@root.prefix}}--dropdown-list">
{{#each items}}
<li data-option data-value="{{value}}" class="{{@root.prefix}}--dropdown-item">
<a class="{{@root.prefix}}--dropdown-link" href="javascript:void(0)" tabindex="-1">{{label}}</a>
</li>
{{/each}}
</ul>
</li>
</ul>
<div data-dropdown{{#if inline}} data-dropdown-type="inline" {{/if}} data-value
class="{{@root.prefix}}--dropdown{{#if up}} {{@root.prefix}}--dropdown--up{{/if}}{{#if light}} {{@root.prefix}}--dropdown--light{{/if}}{{#if inline}} {{@root.prefix}}--dropdown--inline{{/if}} {{@root.prefix}}--dropdown--disabled">
<button disabled class="{{@root.prefix}}--dropdown-text" aria-haspopup="true" aria-expanded="false" aria-controls="{{disabled.idSuffix}}-menu" aria-labelledby="{{disabled.idSuffix}}-label {{disabled.idSuffix}}-value" type="button">
<span class="{{@root.prefix}}--dropdown-text__inner" id="{{disabled.idSuffix}}-value">{{#unless inline}} Dropdown option {{else}}Inline Dropdown label{{/unless}}</span>
<span class="{{@root.prefix}}--dropdown__arrow-container">
{{ carbon-icon 'ChevronDown16' class=(add @root.prefix '--dropdown__arrow') }}
</span>
</button>
<!-- Note: remove `tabindex` from disabled dropdown lists -->
<ul class="{{@root.prefix}}--dropdown-list" id="{{disabled.idSuffix}}-menu" role="menu" id="{{disabled.idSuffix}}-menu" aria-hidden="true" wh-menu-anchor="left" aria-labelledby="{{disabled.idSuffix}}-label">
{{#each items as |item index|}}
<li data-option data-value="{{value}}" class="{{@root.prefix}}--dropdown-item">
<a class="{{@root.prefix}}--dropdown-link" href="javascript:void(0)" tabindex="-1" role="menuitemradio" aria-checked="{{#if index}}false{{else}}true{{/if}}" id="{{../disabled.idSuffix}}-item{{@index}}">{{label}}</a>
</li>
{{/each}}
</ul>
</div>
</div>
</div>

<div class="{{@root.prefix}}--form-item">
<div
class="{{@root.prefix}}--dropdown__wrapper {{#if inline}}{{@root.prefix}}--dropdown__wrapper--inline {{@root.prefix}}--dropdown__wrapper--inline--invalid{{/if}}">
<label for="dropdown-id-invalid" class="{{@root.prefix}}--label">Dropdown
label</label>
<div class="{{@root.prefix}}--dropdown__wrapper {{#if inline}}{{@root.prefix}}--dropdown__wrapper--inline {{@root.prefix}}--dropdown__wrapper--inline--invalid{{/if}}">
<span id="{{invalid.idSuffix}}-label" class="{{@root.prefix}}--label">Dropdown label</span>
{{#unless inline}}
<div class="{{@root.prefix}}--form__helper-text">Optional helper text
here; if message is more than one line text
should wrap (~100 character count maximum)</div>
{{/unless}}
<ul data-dropdown{{#if inline}} data-dropdown-type="inline" {{/if}} data-value id="dropdown-id-invalid"
<div data-dropdown{{#if inline}} data-dropdown-type="inline" {{/if}} data-value
class="{{@root.prefix}}--dropdown {{@root.prefix}}--dropdown--invalid {{#if up}}{{@root.prefix}}--dropdown--up{{/if}} {{#if light}}{{@root.prefix}}--dropdown--light{{/if}}{{#if inline}} {{@root.prefix}}--dropdown--inline{{/if}}"
tabindex="0" data-invalid>
{{ carbon-icon 'WarningFilled16' class=(add @root.prefix '--dropdown__invalid-icon')}}
<li class="{{@root.prefix}}--dropdown-text">
{{#unless inline}} Dropdown option {{else}}
<span class="{{@root.prefix}}--dropdown-text__inner">Inline Dropdown label</span>
{{/unless}}
{{#unless inline}}
</li>
<li class="{{@root.prefix}}--dropdown__arrow-container">
{{/unless}}
{{ carbon-icon 'ChevronDown16' class=(add @root.prefix '--dropdown__arrow') }}
</li>
<li>
<ul class="{{@root.prefix}}--dropdown-list">
{{#each items}}
<li data-option data-value="{{value}}" class="{{@root.prefix}}--dropdown-item">
<a class="{{@root.prefix}}--dropdown-link" href="javascript:void(0)" tabindex="-1">{{label}}</a>
</li>
{{/each}}
</ul>
</li>
</ul>
{{#if inline}}
data-invalid>
<button class="{{@root.prefix}}--dropdown-text" aria-haspopup="true" aria-expanded="false" aria-controls="{{invalid.idSuffix}}-menu" aria-labelledby="{{invalid.idSuffix}}-label {{invalid.idSuffix}}-value" type="button">
{{ carbon-icon 'WarningFilled16' class=(add @root.prefix '--dropdown__invalid-icon')}}
<span class="{{@root.prefix}}--dropdown-text__inner" id="{{invalid.idSuffix}}-value">{{#unless inline}} Dropdown option {{else}}Inline Dropdown label{{/unless}}</span>
<span class="{{@root.prefix}}--dropdown__arrow-container">
{{ carbon-icon 'ChevronDown16' class=(add @root.prefix '--dropdown__arrow') }}
</span>
</button>
<ul class="{{@root.prefix}}--dropdown-list" id="{{invalid.idSuffix}}-menu" role="menu" tabindex="0" id="{{invalid.idSuffix}}-menu" aria-hidden="true" wh-menu-anchor="left" aria-labelledby="{{invalid.idSuffix}}-label">
{{#each items as |item index|}}
<li data-option data-value="{{value}}" class="{{@root.prefix}}--dropdown-item">
<a class="{{@root.prefix}}--dropdown-link" href="javascript:void(0)" tabindex="-1" role="menuitemradio" aria-checked="{{#if index}}false{{else}}true{{/if}}" id="{{../invalid.idSuffix}}-item{{@index}}">{{label}}</a>
</li>
{{/each}}
</ul>
{{#if inline}}
<div class="{{@root.prefix}}--form-requirement">
This is not a validation message
</div>
{{/if}}
</div>
{{#unless inline}}
<div class="{{@root.prefix}}--form-requirement">
This is not a validation message
</div>
{{/if}}
</div>
{{#unless inline}}
<div class="{{@root.prefix}}--form-requirement">
This is not a validation message
{{/unless}}
</div>
{{/unless}}
</div>
Loading

0 comments on commit 3f183ff

Please sign in to comment.