diff --git a/.changeset/perf-dialog-css-has-selector.md b/.changeset/perf-dialog-css-has-selector.md
new file mode 100644
index 00000000000..b4fb349eebc
--- /dev/null
+++ b/.changeset/perf-dialog-css-has-selector.md
@@ -0,0 +1,5 @@
+---
+'@primer/react': patch
+---
+
+perf(Dialog): replace `:has(.Footer)` with `[data-has-footer]` attribute selector for footer border detection
diff --git a/packages/react/src/Dialog/Dialog.module.css b/packages/react/src/Dialog/Dialog.module.css
index ac5a664c148..c87b9321e56 100644
--- a/packages/react/src/Dialog/Dialog.module.css
+++ b/packages/react/src/Dialog/Dialog.module.css
@@ -324,7 +324,7 @@ Add a border between the body and footer if:
- the dialog has a body that can scroll
- the browser supports the `animation-timeline` property and its `scroll()` function
*/
-.Dialog:has(.Footer) {
+.Dialog[data-has-footer] {
--can-scroll: 0;
.DialogOverflowWrapper {
diff --git a/packages/react/src/Dialog/Dialog.test.tsx b/packages/react/src/Dialog/Dialog.test.tsx
index 65297c762c7..c5b25b2fb09 100644
--- a/packages/react/src/Dialog/Dialog.test.tsx
+++ b/packages/react/src/Dialog/Dialog.test.tsx
@@ -40,6 +40,24 @@ describe('Dialog', () => {
await waitFor(() => expect(getByRole('button', {name: 'Footer button'})).toHaveFocus())
})
+ it('sets data-has-footer when footerButtons are provided', () => {
+ const {getByRole} = render(
+ ,
+ )
+ expect(getByRole('dialog')).toHaveAttribute('data-has-footer', '')
+ })
+
+ it('does not set data-has-footer when no footer is rendered', () => {
+ const {getByRole} = render(
+ ,
+ )
+ expect(getByRole('dialog')).not.toHaveAttribute('data-has-footer')
+ })
+
it('calls `onClose` when clicking the close button', async () => {
const user = userEvent.setup()
const onClose = vi.fn()
diff --git a/packages/react/src/Dialog/Dialog.tsx b/packages/react/src/Dialog/Dialog.tsx
index 2a070a88d66..0f5409e930d 100644
--- a/packages/react/src/Dialog/Dialog.tsx
+++ b/packages/react/src/Dialog/Dialog.tsx
@@ -370,6 +370,7 @@ const _Dialog = React.forwardRef