Skip to content
Navigation

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 hrefclassName, target, rel, onClick, ref — is passed through to the resolved component untouched. See LinkProps, which is React.ComponentPropsWithRef<"a"> with href made required.

PropTypeDefaultDescription
hrefstringWhere the link goes. Required, and the one prop the contract insists on — every router link accepts at least this.

LinkProvider

PropTypeDefaultDescription
componentLinkComponenta plain <a>The component every Link in the tree renders through — next/link, React Router's Link, or an adapter around one.

useLinkComponent

PropTypeDefaultDescription
useLinkComponent()() => LinkComponentThe link component from the nearest LinkProvider, or the plain-anchor fallback.