Skip to content

Commit 5faa962

Browse files
marker-daomarker dao ®
andauthored
RadioGroup: Move describedby to the buttons, remove role alert from the element (#32870)
Co-authored-by: marker dao ® <youdontknow@marker-dao.eth>
1 parent a42a44e commit 5faa962

3 files changed

Lines changed: 74 additions & 10 deletions

File tree

packages/devextreme/js/__internal/ui/editor/editor.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,16 @@ class Editor<
270270
return validationErrors;
271271
}
272272

273+
_toggleAriaDescribedBy(value?: string | null): void {
274+
this.setAria('describedby', value);
275+
}
276+
273277
_disposeValidationMessage(): void {
274278
if (this._$validationMessage) {
275279
this._$validationMessage.remove();
276-
this.setAria('describedby', null);
280+
281+
this._toggleAriaDescribedBy(null);
282+
277283
this._$validationMessage = undefined;
278284
this._validationMessage = undefined;
279285
}
@@ -289,6 +295,7 @@ class Editor<
289295
validationStatus,
290296
_showValidationMessage: showValidationMessage,
291297
} = this.option();
298+
292299
const isValid = this.option('isValid') && validationStatus !== VALIDATION_STATUS_INVALID;
293300
const validationErrors = this._getValidationErrors();
294301
const $element = this.$element();
@@ -300,6 +307,7 @@ class Editor<
300307
}
301308

302309
this._disposeValidationMessage();
310+
303311
if (!isValid && validationErrors) {
304312
const {
305313
validationMessageMode,
@@ -309,8 +317,10 @@ class Editor<
309317
} = this.option();
310318

311319
this._$validationMessage = $('<div>').appendTo($element);
320+
312321
const validationMessageContentId = `dx-${new Guid()}`;
313-
this.setAria('describedby', validationMessageContentId);
322+
323+
this._toggleAriaDescribedBy(validationMessageContentId);
314324

315325
// @ts-expect-error ts-error
316326
this._validationMessage = new ValidationMessage(this._$validationMessage, extend({
@@ -324,6 +334,7 @@ class Editor<
324334
boundary: validationBoundary,
325335
contentId: validationMessageContentId,
326336
}, this._options.cache('validationTooltipOptions')));
337+
327338
this._bindInnerWidgetOptions(this._validationMessage, 'validationTooltipOptions');
328339
}
329340
}

packages/devextreme/js/__internal/ui/radio_group/m_radio_group.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,16 @@ class RadioGroup extends Editor<RadioGroupProperties> {
138138
this._setCollectionWidgetOption('selectedItemKeys', this._getSelectedItemKeys(value));
139139
}
140140

141-
_renderValidationState(): void {
142-
super._renderValidationState();
141+
_toggleAriaDescribedBy(value?: string | null): void {
142+
const targets = this.itemElements()?.toArray();
143143

144-
// @ts-expect-error
145-
this._validationMessage?.$content().attr('role', 'alert');
144+
if (!targets?.length) {
145+
return;
146+
}
147+
148+
targets.forEach((element) => {
149+
this.setAria('describedby', value, $(element));
150+
});
146151
}
147152

148153
_optionChanged(args: OptionChanged<RadioGroupProperties>): void {

packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/radioGroup.tests.js

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,16 +238,64 @@ module('layout', moduleConfig, () => {
238238
assert.strictEqual(itemsCount, items.length, `items with the "${RADIO_BUTTON_CLASS}" class were rendered`);
239239
});
240240

241-
test('radioGroup should have role="alert" attribute on validation message', function(assert) {
242-
const $radioGroup = $('#radioGroup').dxRadioGroup({
241+
});
242+
243+
module('accessibility', moduleConfig, () => {
244+
test('validation message should not have role="alert"', function(assert) {
245+
const $radioGroup = createRadioGroup({
243246
items: [1, 2, 3],
244247
isValid: false,
245-
validationError: 'Some error',
248+
validationError: { message: 'Some error' },
246249
validationMessageMode: 'always',
247250
});
248251
const $validationMessage = $radioGroup.find(`.${INVALID_MESSAGE_CONTENT}`);
249252

250-
assert.strictEqual($validationMessage.attr('role'), 'alert');
253+
assert.notStrictEqual($validationMessage.attr('role'), 'alert', 'validation message does not have role="alert"');
254+
});
255+
256+
test('root element should not have aria-describedby when invalid', function(assert) {
257+
const $radioGroup = createRadioGroup({
258+
items: [1, 2, 3],
259+
isValid: false,
260+
validationError: { message: 'Some error' },
261+
validationMessageMode: 'always',
262+
});
263+
264+
assert.strictEqual($radioGroup.attr('aria-describedby'), undefined, 'root element does not have aria-describedby');
265+
});
266+
267+
test('each radio button should have aria-describedby referencing the validation message when invalid', function(assert) {
268+
const $radioGroup = createRadioGroup({
269+
items: [1, 2, 3],
270+
isValid: false,
271+
validationError: { message: 'Some error' },
272+
validationMessageMode: 'always',
273+
});
274+
const instance = getInstance($radioGroup);
275+
const contentId = $radioGroup.find(`.${INVALID_MESSAGE_CONTENT}`).attr('id');
276+
const $buttons = $(instance.itemElements());
277+
278+
assert.ok(contentId, 'validation message content has an id');
279+
$buttons.each(function() {
280+
assert.strictEqual($(this).attr('aria-describedby'), contentId, 'radio button references validation message');
281+
});
282+
});
283+
284+
test('aria-describedby should be removed from radio buttons when validation state becomes valid', function(assert) {
285+
const $radioGroup = createRadioGroup({
286+
items: [1, 2, 3],
287+
isValid: false,
288+
validationError: { message: 'Some error' },
289+
validationMessageMode: 'always',
290+
});
291+
const instance = getInstance($radioGroup);
292+
293+
instance.option('isValid', true);
294+
295+
const $buttons = $(instance.itemElements());
296+
$buttons.each(function() {
297+
assert.strictEqual($(this).attr('aria-describedby'), undefined, 'aria-describedby is removed from radio button');
298+
});
251299
});
252300
});
253301

0 commit comments

Comments
 (0)