diff --git a/frontend/packages/dashboard/src/modal.js b/frontend/packages/dashboard/src/modal.js index 5e6fd406..01ff8f24 100644 --- a/frontend/packages/dashboard/src/modal.js +++ b/frontend/packages/dashboard/src/modal.js @@ -52,9 +52,19 @@ export function openDialog(opts = {}) { return { spec: b, btn }; }); - const box = el('div', { class: 'tc-box', role: 'dialog', 'aria-modal': 'true' }, - title ? el('div', { class: 'tc-title' }, title) : null, - message ? el('div', { class: 'tc-message' }, message) : null, + // Give the dialog an accessible name: label it by its title if present, + // else by its message, via `aria-labelledby` (a11y — role=dialog needs a + // name). Only the labelling element carries the id. + const labelId = 'tc-dlg-' + Math.random().toString(36).slice(2, 9); + const titleEl = title ? el('div', { class: 'tc-title', id: labelId }, title) : null; + const messageEl = message + ? el('div', title ? { class: 'tc-message' } : { class: 'tc-message', id: labelId }, message) + : null; + const boxAttrs = { class: 'tc-box', role: 'dialog', 'aria-modal': 'true' }; + if (titleEl || messageEl) boxAttrs['aria-labelledby'] = labelId; + const box = el('div', boxAttrs, + titleEl, + messageEl, content || null, el('div', { class: 'tc-actions' }, ...btnEls.map((b) => b.btn)));