How to Configure Astryx Link Component for Next.js, React Router, and Other React Routers
Astryx's Link component is router-agnostic and renders a native <a> by default, but you can replace it with any React router's link component via the LinkProvider pattern without changing your API.
The Astryx design system (facebook/astryx) provides a flexible, context-based solution for integrating its Link component with different routing libraries. Whether you're using Next.js, React Router, TanStack Router, or another solution, you can swap the underlying rendering behavior while preserving Astryx's styling, accessibility features, and tooltip support.
How the Link Provider Pattern Works
Astryx uses three core pieces to enable router flexibility, all located in packages/core/src/Link/:
LinkProvider.tsx– Supplies a custom link component to any subtree via React contextuseLinkComponent.ts– Resolves which component to render and handles prop mappingLink.tsx– The consumer that applies Astryx's visual and behavioral layer
The resolution hierarchy in useLinkComponent.ts follows this priority: per-instance as prop > provider component > native <a>. When a custom component replaces the default anchor, Astryx automatically adds a to prop (mirroring href) so routers expecting to work without adapter code.
Configuring Astryx Link for Next.js
Next.js uses next/link, which expects an href prop. Since Astryx also uses href natively, the integration is straightforward.
Wrap your root layout or app component with LinkProvider:
// app/layout.tsx (Next.js 13+ App Router)
import {LinkProvider} from '@astryxdesign/core';
import NextLink from 'next/link';
export default function RootLayout({children}: {children: React.ReactNode}) {
return (
<html>
<body>
<LinkProvider component={NextLink}>
{children}
</LinkProvider>
</body>
</html>
);
}
Now all Astryx Link components render as next/link instances:
import {Link} from '@astryxdesign/core';
export function Navigation() {
return (
<nav>
<Link href="/products">Products</Link>
<Link href="/docs" isExternalLink>Documentation</Link>
</nav>
);
}
The isExternalLink prop still works correctly—useLinkComponent.ts detects external URLs and appropriately falls back to standard anchor behavior even when a custom component is provided.
Configuring Astryx Link for React Router
React Router's <Link> component expects a to prop instead of href. Astryx handles this automatically through createLinkWithTo in useLinkComponent.ts, which wraps custom components to inject to={href}.
Set up your app with BrowserRouter and LinkProvider:
// src/App.tsx
import {BrowserRouter} from 'react-router-dom';
import {LinkProvider} from '@astryxdesign/core';
import {Link as RouterLink} from 'react-router-dom';
export function App() {
return (
<BrowserRouter>
<LinkProvider component={RouterLink}>
{/* Your application routes */}
</LinkProvider>
</BrowserRouter>
);
}
Write navigation using standard Astryx href props:
import {Link} from '@astryxdesign/core';
export function AdminSidebar() {
return (
<aside>
<ul>
<li><Link href="/dashboard">Dashboard</Link></li>
<li><Link href="/users">User Management</Link></li>
<li><Link href="/reports">Reports</Link></li>
</ul>
</aside>
);
}
Behind the scenes in useLinkComponent.ts, the wrapper translates your href into both href and to props, satisfying React Router's requirements without code changes.
Per-Instance Component Override with the as Prop
For mixed routing scenarios or one-off exceptions, use the as prop to override the component for a single Link instance. This bypasses both the provider value and the default anchor.
import {Link} from '@astryxdesign/core';
import {Link as RouterLink} from 'react-router-dom';
import NextLink from 'next/link';
export function HybridNavigation() {
return (
<>
{/* Uses provider default (Next.js in this example) */}
<Link href="/home">Home</Link>
{/* Overrides to React Router Link for this instance only */}
<Link href="/admin" as={RouterLink}>Admin Panel</Link>
{/* Forces native anchor despite provider */}
<Link href="/legacy" as="a">Legacy Page</Link>
</>
);
}
The as prop accepts any valid React component type or the string 'a', giving you granular control when needed.
Key Source Files in Astryx
Understanding the implementation details helps debug integration issues:
| File | Purpose |
|---|---|
LinkProvider.tsx |
Context provider that stores the custom link component |
useLinkComponent.ts |
Hook resolving component priority and injecting to prop |
Link.tsx |
Core component applying theme, transitions, and accessibility |
LinkContext.ts |
React context definition for provider/consumer pair |
Link.doc.mjs |
API documentation and prop specifications |
The source code reveals that useLinkComponent uses the experimental use(LinkContext) API (React 18+) for context reading, and that createLinkWithTo is only applied when the resolved component isn't the native 'a' string.
Complete TypeScript Example: Multi-Router Setup
Here's a practical pattern for applications transitioning between routers or using micro-frontends with different routing solutions:
// components/RouterAwareLink.tsx
import {Link as AstryxLink, LinkProps} from '@astryxdesign/core';
import {Link as RouterLink} from 'react-router-dom';
import NextLink from 'next/link';
type RouterType = 'next' | 'react-router' | 'default';
interface RouterAwareLinkProps extends Omit<LinkProps, 'as'> {
router?: RouterType;
}
const routerComponents: Record<RouterType, React.ComponentType<any>> = {
next: NextLink,
'react-router': RouterLink,
default: 'a',
};
export function RouterAwareLink({router = 'default', ...props}: RouterAwareLinkProps) {
return <AstryxLink {...props} as={routerComponents[router]} />;
}
Usage across your application remains consistent:
// In a Next.js page
<RouterAwareLink router="next" href="/about">About</RouterAwareLink>
// In a React Router subtree
<RouterAwareLink router="react-router" href="/profile">Profile</RouterAwareLink>
// External or static links
<RouterAwareLink href="https://example.com" isExternalLink>External</RouterAwareLink>
Summary
- Astryx
Linkis router-agnostic by design — start with a native<a>and upgrade to framework-specific components viaLinkProvider LinkProvidersets the default for all descendant links through React context defined inLinkContext.tsuseLinkComponenthandles the mapping — resolves priority chain (as> provider >'a') and auto-injectstofor React Router compatibility- No adapter code needed — the internal
createLinkWithTowrapper inuseLinkComponent.tsbridgeshrefandtoprop differences automatically - Granular control available — the
asprop on individualLinkinstances overrides context for mixed-router scenarios
Frequently Asked Questions
Does Astryx Link work with TanStack Router?
Yes. TanStack Router's Link component uses a to prop like React Router, so the same configuration pattern applies. Wrap your app with LinkProvider and pass TanStack's Link component—the automatic to injection in useLinkComponent.ts handles the rest.
Can I use different routers in the same application?
Absolutely. The as prop on individual Link instances overrides the LinkProvider value. You can nest multiple providers at different tree levels, or use per-instance overrides to mix Next.js, React Router, and native links as needed.
What happens if I don't configure a provider?
Without LinkProvider, all Astryx Link components render as native <a> elements. You retain full styling, accessibility, and tooltip functionality, but lose client-side navigation benefits from your framework's router.
Does the isExternalLink prop work with custom routers?
Yes. The external link detection logic runs before component resolution in Link.tsx. External URLs automatically render as native anchors with appropriate rel and target attributes, regardless of your LinkProvider configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →