From 3e5704cb2948b2e02d7d08f283d3f814cf31eee6 Mon Sep 17 00:00:00 2001
From: Fnine59 <36078040+Fnine59@users.noreply.github.com>
Date: Tue, 18 Aug 2026 23:03:07 +0000
Subject: [PATCH] fix(solid-router): preserve caller roles on enabled links
---
.changeset/solid-link-role.md | 5 +++
packages/solid-router/src/link.tsx | 2 +-
packages/solid-router/tests/link.test.tsx | 45 +++++++++++++++++++++++
3 files changed, 51 insertions(+), 1 deletion(-)
create mode 100644 .changeset/solid-link-role.md
diff --git a/.changeset/solid-link-role.md b/.changeset/solid-link-role.md
new file mode 100644
index 0000000000..b66e1c1dc6
--- /dev/null
+++ b/.changeset/solid-link-role.md
@@ -0,0 +1,5 @@
+---
+'@tanstack/solid-router': patch
+---
+
+Preserve caller-provided roles on enabled links.
diff --git a/packages/solid-router/src/link.tsx b/packages/solid-router/src/link.tsx
index c5d3691672..ccc1773736 100644
--- a/packages/solid-router/src/link.tsx
+++ b/packages/solid-router/src/link.tsx
@@ -534,7 +534,7 @@ export function useLinkProps<
href: () => hrefOption()?.href,
disabled: () => !!local.disabled,
target: () => local.target,
- role: () => (local.disabled ? 'link' : undefined),
+ role: () => (local.disabled ? 'link' : propsSafeToSpread.role),
'aria-disabled': () => (local.disabled ? 'true' : undefined),
'data-status': () => (isActive() ? 'active' : undefined),
'aria-current': () => (isActive() ? 'page' : undefined),
diff --git a/packages/solid-router/tests/link.test.tsx b/packages/solid-router/tests/link.test.tsx
index f4de9b831c..3a5fe05fab 100644
--- a/packages/solid-router/tests/link.test.tsx
+++ b/packages/solid-router/tests/link.test.tsx
@@ -180,6 +180,51 @@ describe('Link', () => {
).rejects.toThrow()
})
+ test('preserves a caller-provided role while enabled', async () => {
+ const [disabled, setDisabled] = Solid.createSignal(false)
+ const rootRoute = createRootRoute()
+ const indexRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/',
+ component: () => (
+ <>
+
+
+ Posts
+
+ >
+ ),
+ })
+ const postsRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ path: '/posts',
+ })
+ const router = createRouter({
+ routeTree: rootRoute.addChildren([indexRoute, postsRoute]),
+ history,
+ })
+
+ render(() => )
+
+ const link = await screen.findByTestId('role-link')
+ const toggle = screen.getByRole('button', { name: 'Toggle disabled' })
+
+ expect(link).toHaveAttribute('role', 'button')
+
+ fireEvent.click(toggle)
+ await waitFor(() => expect(link).toHaveAttribute('role', 'link'))
+
+ fireEvent.click(toggle)
+ await waitFor(() => expect(link).toHaveAttribute('role', 'button'))
+ })
+
test('does not forward internal Link props to the DOM', async () => {
const internalPropNames = [
'activeProps',