Link
A link that routes through your framework instead of reloading the page. It resolves its element from LinkProvider at render, so the library never imports a router — and works as a plain anchor when there is no provider.
Import
import {
Link,
LinkProvider,
useLinkComponent,
} from "@mikenotthepope/substrateui"Why this exists
The suite renders navigation in places you do not control — a breadcrumb inside a block, a sidebar item inside a shell. If those were plain anchors, every one would be a full page load in a routed app; if they imported next/link, the library would only work in Next.
So navigation goes through React context. You name your framework's link once, and every Link in the tree — including the ones inside blocks and organisms — routes client-side. With no provider they fall back to <a>, so the suite works out of the box in any React app.
Wiring the provider
Once, as high in the tree as your framework allows — the root layout in Next, the router's children elsewhere.
Every Link below this point now navigates through the Next router.
// app/layout.tsx
import NextLink from "next/link"
import { LinkProvider } from "@mikenotthepope/substrateui"
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<LinkProvider component={NextLink}>{children}</LinkProvider>
</body>
</html>
)
}Routers that use a different prop
The contract is href. React Router and Remix take to, so they need a two-line adapter — declared outside your component, not inline, or React remounts every link on each render.
The same shape works for TanStack Router, or any link that takes a destination and spreads the rest onto an anchor.
import { Link as RouterLink } from "react-router-dom"
import { LinkProvider, type LinkComponent } from "@mikenotthepope/substrateui"
// Declared at module scope: a component created during render is a new type
// every time, and React unmounts and remounts the whole subtree.
const RouterAdapter: LinkComponent = ({ href, ...props }) => (
<RouterLink to={href} {...props} />
)
<LinkProvider component={RouterAdapter}>{children}</LinkProvider>Reaching the link from your own components
useLinkComponent returns whatever the nearest provider supplied, for components of your own that need a router-aware link without hard-coding a framework. It is the same hook Link uses.
Outside a provider the hook returns the plain-anchor fallback, so this never has to branch.
function BackToTop({ children }: { children: React.ReactNode }) {
const Anchor = useLinkComponent()
return <Anchor href="#top" className="text-sm underline">{children}</Anchor>
}Accessibility
Whatever comes out is an anchor with an href, so it is focusable, announced as a link, and opens in a new tab on middle-click — none of which a div with an onClick gives you. If an action is not navigation, use a Button.
Link supplies no styling: no underline, no colour. An underline is the only link cue that does not depend on seeing colour, so removing it in body text leaves colour-blind readers unable to find the link. Keep it, or replace it with a cue that is not colour.
The link text must say where it goes on its own. "Read more" repeated down a page gives a screen-reader user a list of identical destinations.
An external link should say so — target="_blank" with rel="noreferrer" and something in the accessible name noting it opens a new tab, since an unannounced tab switch strands people using magnification or a screen reader.
API Reference
Every prop other than href — className, target, rel, onClick, ref — is passed through to the resolved component untouched. See LinkProps, which is React.ComponentPropsWithRef<"a"> with href made required.
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | — | Where the link goes. Required, and the one prop the contract insists on — every router link accepts at least this. |
LinkProvider
| Prop | Type | Default | Description |
|---|---|---|---|
component | LinkComponent | a plain <a> | The component every Link in the tree renders through — next/link, React Router's Link, or an adapter around one. |
useLinkComponent
| Prop | Type | Default | Description |
|---|---|---|---|
useLinkComponent() | () => LinkComponent | — | The link component from the nearest LinkProvider, or the plain-anchor fallback. |