diff --git a/packages/webawesome/docs/docs/resources/changelog.md b/packages/webawesome/docs/docs/resources/changelog.md
index 102e640f9..444911683 100644
--- a/packages/webawesome/docs/docs/resources/changelog.md
+++ b/packages/webawesome/docs/docs/resources/changelog.md
@@ -36,6 +36,7 @@ Components with the Experimental badge sh
- Fixed a bug in `` that prevented tooltips from showing when disconnecting and then reconnecting to the DOM [issue:1595]
- Fixed a bug that caused the required `*` in form labels to have incorrect spacing in `` and `` [issue:1472]
- Fixed a bug in `` and `` that caused the component to prematurely hide when certain child elements are used [pr:1636]
+- Fixed a bug in `` and `` that prevented dots and other valid ID characters from being used [issue:1648]
- Improved autofill styles in `` so they span the entire width of the visual input [issue:1439]
- Modified `` to only show the tooltip on the handle being dragged when in range mode [issue:1320]
- Improved [text utilities](/docs/utilities/text/) so that each size modifier always exactly matches the applied font size [pr:1602]
diff --git a/packages/webawesome/src/components/popover/popover.ts b/packages/webawesome/src/components/popover/popover.ts
index 376263663..63ed3a14a 100644
--- a/packages/webawesome/src/components/popover/popover.ts
+++ b/packages/webawesome/src/components/popover/popover.ts
@@ -230,7 +230,7 @@ export default class WaPopover extends WebAwesomeElement {
return;
}
- const newAnchor = this.for ? rootNode.querySelector(`#${this.for}`) : null;
+ const newAnchor = this.for ? rootNode.getElementById(this.for) : null;
const oldAnchor = this.anchor;
if (newAnchor === oldAnchor) {
diff --git a/packages/webawesome/src/components/tooltip/tooltip.ts b/packages/webawesome/src/components/tooltip/tooltip.ts
index 9c16798c5..abbbcfd85 100644
--- a/packages/webawesome/src/components/tooltip/tooltip.ts
+++ b/packages/webawesome/src/components/tooltip/tooltip.ts
@@ -137,8 +137,7 @@ export default class WaTooltip extends WebAwesomeElement {
this.eventController.abort();
if (this.anchor) {
- const label = this.anchor.getAttribute('aria-labelledby') || '';
- this.anchor.setAttribute('aria-labelledby', label.replace(this.id, ''));
+ this.removeFromAriaLabelledBy(this.anchor, this.id);
}
}
@@ -202,6 +201,34 @@ export default class WaTooltip extends WebAwesomeElement {
return triggers.includes(triggerType);
}
+ /** Adds the tooltip ID to the aria-labelledby attribute */
+ private addToAriaLabelledBy(element: Element, id: string) {
+ const currentLabel = element.getAttribute('aria-labelledby') || '';
+ const labels = currentLabel.split(/\s+/).filter(Boolean);
+
+ // Only add if not already present
+ if (!labels.includes(id)) {
+ labels.push(id);
+ element.setAttribute('aria-labelledby', labels.join(' '));
+ }
+ }
+
+ /** Removes the tooltip ID from the aria-labelledby attribute */
+ private removeFromAriaLabelledBy(element: Element, id: string) {
+ const currentLabel = element.getAttribute('aria-labelledby') || '';
+ const labels = currentLabel.split(/\s+/).filter(Boolean);
+
+ // Remove the ID
+ const filteredLabels = labels.filter(label => label !== id);
+
+ if (filteredLabels.length > 0) {
+ element.setAttribute('aria-labelledby', filteredLabels.join(' '));
+ } else {
+ // Remove the attribute if empty
+ element.removeAttribute('aria-labelledby');
+ }
+ }
+
@watch('open', { waitUntilFirstUpdate: true })
async handleOpenChange() {
if (this.open) {
@@ -252,7 +279,7 @@ export default class WaTooltip extends WebAwesomeElement {
return;
}
- const newAnchor = this.for ? rootNode.querySelector(`#${this.for}`) : null;
+ const newAnchor = this.for ? rootNode.getElementById(this.for) : null;
const oldAnchor = this.anchor;
if (newAnchor === oldAnchor) {
@@ -261,9 +288,6 @@ export default class WaTooltip extends WebAwesomeElement {
const { signal } = this.eventController;
- // "\\b" is a space boundary, used for making sure we don't add the tooltip to aria-labelledby twice.
- const labelRegex = new RegExp(`\\b${this.id}\\b`);
-
if (newAnchor) {
/**
* We use `aria-labelledby` because it seems to have the most consistent screen reader experience.
@@ -272,10 +296,7 @@ export default class WaTooltip extends WebAwesomeElement {
* whereas with `aria-labelledby` it'll still read on first focus. The APG does and WAI-ARIA does recommend aria-describedby
* so perhaps once we have cross-root aria, we can revisit this decision.
*/
- const currentLabel = newAnchor.getAttribute('aria-labelledby') || '';
- if (!currentLabel.match(labelRegex)) {
- newAnchor.setAttribute('aria-labelledby', currentLabel + ' ' + this.id);
- }
+ this.addToAriaLabelledBy(newAnchor, this.id);
newAnchor.addEventListener('blur', this.handleBlur, { capture: true, signal });
newAnchor.addEventListener('focus', this.handleFocus, { capture: true, signal });
@@ -285,8 +306,7 @@ export default class WaTooltip extends WebAwesomeElement {
}
if (oldAnchor) {
- const label = oldAnchor.getAttribute('aria-labelledby') || '';
- oldAnchor.setAttribute('aria-labelledby', label.replace(labelRegex, ''));
+ this.removeFromAriaLabelledBy(oldAnchor, this.id);
oldAnchor.removeEventListener('blur', this.handleBlur, { capture: true });
oldAnchor.removeEventListener('focus', this.handleFocus, { capture: true });
oldAnchor.removeEventListener('click', this.handleClick);