diff --git a/.changeset/hot-melons-jump.md b/.changeset/hot-melons-jump.md
new file mode 100644
index 00000000000..5feeafee472
--- /dev/null
+++ b/.changeset/hot-melons-jump.md
@@ -0,0 +1,5 @@
+---
+"@primer/react": patch
+---
+
+Banner: Should prefer aria-labelled-by over aria-label
diff --git a/packages/react/src/Banner/Banner.test.tsx b/packages/react/src/Banner/Banner.test.tsx
index ef993da80a1..bf17f308c97 100644
--- a/packages/react/src/Banner/Banner.test.tsx
+++ b/packages/react/src/Banner/Banner.test.tsx
@@ -50,6 +50,25 @@ describe('Banner', () => {
expect(screen.getByRole('region')).toHaveAttribute('aria-label', 'Test')
})
+ it('should prefer aria-labelledby over aria-label and not set both', () => {
+ render(
+
+ Explicit Banner Title
+ ,
+ )
+
+ const region = screen.getByRole('region', {name: 'Explicit Banner Title'})
+ expect(region).toHaveAttribute('aria-labelledby', 'my-banner-title')
+ expect(region).not.toHaveAttribute('aria-label')
+ })
+
+ it('should only set aria-label when aria-labelledby is not provided', () => {
+ render()
+ const region = screen.getByRole('region')
+ expect(region).toHaveAttribute('aria-label', 'Custom Label')
+ expect(region).not.toHaveAttribute('aria-labelledby')
+ })
+
it('should default the title to a h2', () => {
render()
expect(screen.getByRole('heading', {level: 2})).toBeInTheDocument()
diff --git a/packages/react/src/Banner/Banner.tsx b/packages/react/src/Banner/Banner.tsx
index b4921775c3e..3b79f88ad37 100644
--- a/packages/react/src/Banner/Banner.tsx
+++ b/packages/react/src/Banner/Banner.tsx
@@ -85,6 +85,7 @@ const labels: Record = {
export const Banner = React.forwardRef(function Banner(
{
'aria-label': label,
+ 'aria-labelledby': labelledBy,
children,
className,
description,
@@ -131,7 +132,8 @@ export const Banner = React.forwardRef(function Banner
return (