diff --git a/.changeset/good-rats-bathe.md b/.changeset/good-rats-bathe.md
deleted file mode 100644
index 5f180cf0ba46..000000000000
--- a/.changeset/good-rats-bathe.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@astrojs/db": patch
----
-
-Includes `./virtual.d.ts` file that was previously unpublished
diff --git a/.changeset/tough-moose-prove.md b/.changeset/tough-moose-prove.md
new file mode 100644
index 000000000000..f4d462c09e32
--- /dev/null
+++ b/.changeset/tough-moose-prove.md
@@ -0,0 +1,5 @@
+---
+"astro": patch
+---
+
+Fixes some false positive in the dev toolbar a11y audits, by adding the `a` element to the list of interactive elements.
diff --git a/packages/astro/e2e/dev-toolbar-audits.test.js b/packages/astro/e2e/dev-toolbar-audits.test.js
index a9d0dd114d9f..2195aa9f9536 100644
--- a/packages/astro/e2e/dev-toolbar-audits.test.js
+++ b/packages/astro/e2e/dev-toolbar-audits.test.js
@@ -43,4 +43,18 @@ test.describe('Dev Toolbar - Audits', () => {
// Toggle app off
await appButton.click();
});
+
+ test('does not warn for non-interactive element', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/a11y-exceptions'));
+
+ const toolbar = page.locator('astro-dev-toolbar');
+ const appButton = toolbar.locator('button[data-app-id="astro:audit"]');
+ await appButton.click();
+
+ const auditCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="astro:audit"]');
+ const auditHighlights = auditCanvas.locator('astro-dev-toolbar-highlight');
+
+ const count = await auditHighlights.count();
+ expect(count).toEqual(0);
+ });
});
diff --git a/packages/astro/e2e/fixtures/dev-toolbar/src/pages/a11y-exceptions.astro b/packages/astro/e2e/fixtures/dev-toolbar/src/pages/a11y-exceptions.astro
new file mode 100644
index 000000000000..0da2c272d363
--- /dev/null
+++ b/packages/astro/e2e/fixtures/dev-toolbar/src/pages/a11y-exceptions.astro
@@ -0,0 +1,6 @@
+---
+
+---
+
+
+
diff --git a/packages/astro/src/runtime/client/dev-toolbar/apps/audit/a11y.ts b/packages/astro/src/runtime/client/dev-toolbar/apps/audit/a11y.ts
index 45b94b31f6be..28754310bffa 100644
--- a/packages/astro/src/runtime/client/dev-toolbar/apps/audit/a11y.ts
+++ b/packages/astro/src/runtime/client/dev-toolbar/apps/audit/a11y.ts
@@ -42,7 +42,25 @@ const a11y_required_attributes = {
object: ['title', 'aria-label', 'aria-labelledby'],
};
-const interactiveElements = ['button', 'details', 'embed', 'iframe', 'label', 'select', 'textarea'];
+const MAYBE_INTERACTIVE = new Map([
+ ['a', 'href'],
+ ['input', 'type'],
+ ['audio', 'controls'],
+ ['img', 'usemap'],
+ ['object', 'usemap'],
+ ['video', 'controls'],
+]);
+
+const interactiveElements = [
+ 'button',
+ 'details',
+ 'embed',
+ 'iframe',
+ 'label',
+ 'select',
+ 'textarea',
+ ...MAYBE_INTERACTIVE.keys(),
+];
const labellableElements = ['input', 'meter', 'output', 'progress', 'select', 'textarea'];
@@ -187,6 +205,15 @@ const ariaRoles = new Set(
)
);
+function isInteractive(element: Element): boolean {
+ const attribute = MAYBE_INTERACTIVE.get(element.localName);
+ if (attribute) {
+ return element.hasAttribute(attribute);
+ }
+
+ return true;
+}
+
export const a11y: AuditRuleWithSelector[] = [
{
code: 'a11y-accesskey',
@@ -434,6 +461,7 @@ export const a11y: AuditRuleWithSelector[] = [
'Interactive HTML elements like `` and `