Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 28d4bf2

Browse files
jeyoshimikara
authored andcommitted
fix(select): accessibility fixes allowing screen readers (VoiceOver) to (#10760)
Addresses some points in #9908.
1 parent 17f09dc commit 28d4bf2

File tree

2 files changed

+28
-8
lines changed

2 files changed

+28
-8
lines changed

src/components/select/select.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,11 @@ function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $
202202
}
203203

204204
// There's got to be an md-content inside. If there's not one, let's add it.
205-
if (!element.find('md-content').length) {
205+
var mdContentEl = element.find('md-content');
206+
if (!mdContentEl.length) {
206207
element.append(angular.element('<md-content>').append(element.contents()));
207208
}
209+
mdContentEl.attr('role', 'presentation');
208210

209211

210212
// Add progress spinner for md-options-loading
@@ -258,8 +260,8 @@ function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $
258260
// Use everything that's left inside element.contents() as the contents of the menu
259261
var multipleContent = isMultiple ? 'multiple' : '';
260262
var selectTemplate = '' +
261-
'<div class="md-select-menu-container" aria-hidden="true">' +
262-
'<md-select-menu {0}>{1}</md-select-menu>' +
263+
'<div class="md-select-menu-container" aria-hidden="true" role="presentation">' +
264+
'<md-select-menu role="presentation" {0}>{1}</md-select-menu>' +
263265
'</div>';
264266

265267
selectTemplate = $mdUtil.supplant(selectTemplate, [multipleContent, element.html()]);
@@ -521,7 +523,10 @@ function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $
521523

522524
var containerId = 'select_container_' + $mdUtil.nextUid();
523525
selectContainer.attr('id', containerId);
524-
ariaAttrs['aria-owns'] = containerId;
526+
// Only add aria-owns if element ownership is NOT represented in the DOM.
527+
if (!element.find('md-select-menu').length) {
528+
ariaAttrs['aria-owns'] = containerId;
529+
}
525530
element.attr(ariaAttrs);
526531

527532
scope.$on('$destroy', function() {
@@ -1075,6 +1080,7 @@ function OptgroupDirective() {
10751080
el.prepend(labelElement);
10761081
}
10771082
labelElement.addClass('md-container-ignore');
1083+
labelElement.attr('aria-hidden', 'true');
10781084
if (attrs.label) labelElement.text(attrs.label);
10791085
}
10801086
}
@@ -1149,6 +1155,7 @@ function SelectProvider($$interimElementProvider) {
11491155
.removeClass('md-active')
11501156
.attr('aria-hidden', 'true')
11511157
.css('display', 'none');
1158+
element.parent().find('md-select-value').removeAttr('aria-hidden');
11521159

11531160
announceClosed(opts);
11541161

@@ -1175,6 +1182,7 @@ function SelectProvider($$interimElementProvider) {
11751182
opts.alreadyOpen = true;
11761183
opts.cleanupInteraction = activateInteraction();
11771184
opts.cleanupResizing = activateResizing();
1185+
autoFocus(opts.focusedNode);
11781186

11791187
return response;
11801188
}, opts.hideBackdrop);
@@ -1188,6 +1196,11 @@ function SelectProvider($$interimElementProvider) {
11881196
* and scalings...
11891197
*/
11901198
function showDropDown(scope, element, opts) {
1199+
if (opts.parent !== element.parent()) {
1200+
element.parent().attr('aria-owns', element.attr('id'));
1201+
}
1202+
element.parent().find('md-select-value').attr('aria-hidden', 'true');
1203+
11911204
opts.parent.append(element);
11921205

11931206
return $q(function(resolve, reject) {
@@ -1208,7 +1221,7 @@ function SelectProvider($$interimElementProvider) {
12081221

12091222
/**
12101223
* Initialize container and dropDown menu positions/scale, then animate
1211-
* to show... and autoFocus.
1224+
* to show.
12121225
*/
12131226
function positionAndFocusMenu() {
12141227
return $q(function(resolve) {
@@ -1223,7 +1236,6 @@ function SelectProvider($$interimElementProvider) {
12231236
element.addClass('md-active');
12241237
info.dropDown.element.css(animator.toCss({transform: ''}));
12251238

1226-
autoFocus(opts.focusedNode);
12271239
resolve();
12281240
});
12291241

src/components/select/select.spec.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,19 @@ describe('<md-select>', function() {
9292
expect(container.classList.contains('test')).toBe(true);
9393
});
9494

95-
it('sets aria-owns between the select and the container', function() {
95+
it('does not set aria-owns on select if DOM ownership is implied', function() {
9696
var select = setupSelect('ng-model="val"').find('md-select');
9797
var ownsId = select.attr('aria-owns');
98+
expect(select.find('md-option')).toBeTruthy();
99+
expect(ownsId).toBeFalsy();
100+
});
101+
102+
it('sets aria-owns between the select and the container if element moved outside parent', function() {
103+
var select = setupSelect('ng-model="val"').find('md-select');
104+
openSelect(select);
105+
var ownsId = select.attr('aria-owns');
98106
expect(ownsId).toBeTruthy();
99-
var containerId = select[0].querySelector('.md-select-menu-container').getAttribute('id');
107+
var containerId = $document[0].querySelector('.md-select-menu-container').getAttribute('id');
100108
expect(ownsId).toBe(containerId);
101109
});
102110

0 commit comments

Comments
 (0)