# Routing

How the links of ferry-ui work with React Router, Next.js, TanStack Router or plain anchors.

ferry-ui does not import a router. A component that opens a page accepts an `href` string. With no setup, it renders a plain `<a>` element.

## Write an adapter

An adapter is a component that renders the link of your router. It gets `href` and the attributes of an anchor. It must give all these props to the link.

Define the adapter at module level, not in a component.

```tsx title="React Router"

```

```tsx title="Next.js"

```

```tsx title="TanStack Router"

```

ferry-ui gives a plain string to the adapter. If your router has typed routes, cast `href` in the adapter.

## Mount the provider

Give the adapter to [LinkProvider](/docs/utilities/link-provider), one time, at the root of the app. All the links of ferry-ui below it then go through your router.

```tsx title="providers.tsx"

  return <LinkProvider component={RouterLink}>{children}</LinkProvider>
}
```

## Mark the current page

ferry-ui does not know the current page. Your router knows it. Set `active` on the navigation item of the current page.

```tsx title="app-frame.tsx"
// `pathname` comes from your router.
const items: NavItem[] = [
  { id: 'projects', label: 'Projects', href: '/projects', active: pathname.startsWith('/projects') },
  { id: 'members', label: 'Members', href: '/members', active: pathname.startsWith('/members') },
]
```

In this demo, a small context does the work of the router. The adapter sends each click to it.

```tsx
import * as React from 'react'
import { InnerMenu, LinkProvider, type LinkComponent, type NavGroup } from 'ferry-ui'

// This context does the work of a router in the demo: a click changes the location.
const NavigateContext = React.createContext<(href: string) => void>(() => {})

// The adapter. In an app, it renders the link of the router: <Link to={href} {...props} />.
const DemoLink: LinkComponent = ({ href, onClick, ...props }) => {
  const navigate = React.useContext(NavigateContext)
  return (
    <a
      href={href}
      {...props}
      onClick={(event) => {
        onClick?.(event)
        event.preventDefault()
        navigate(href)
      }}
    />
  )
}

const PAGES = [
  { id: 'profile', label: 'Profile', href: '#profile' },
  { id: 'members', label: 'Members', href: '#members' },
  { id: 'billing', label: 'Billing', href: '#billing' },
]

export default function ActiveFromRouter() {
  const [location, setLocation] = React.useState('#members')
  // The location of the router gives the active item.
  const groups: NavGroup[] = [
    { id: 'settings', items: PAGES.map((page) => ({ ...page, active: page.href === location })) },
  ]

  return (
    <NavigateContext.Provider value={setLocation}>
      <LinkProvider component={DemoLink}>
        <div className="flex w-full max-w-md overflow-hidden rounded-lg border">
          <InnerMenu groups={groups} label="Settings" mobileTabs={false} className="w-44 xl:w-44" />
          <p className="p-5 text-[13px] text-foreground-light">
            Location of the router: <code className="text-foreground">{location}</code>
          </p>
        </div>
      </LinkProvider>
    </NavigateContext.Provider>
  )
}
```

## Components that render links

| Area | Components |
| --- | --- |
| Navigation | `IconRail`, `IconRailItem`, `MobileNav`, `InnerMenu`, `CommandMenu`, `ResourceSwitcher` |
| Top bar | `TopBarLogo`, `TopBarSegment`, `TopBarIconButton` |
| Page | `BreadcrumbLink`, `PageBackLink` |
| Content | `ResourceCard`, `DescriptionItem` |

Each of these components also has a `linkComponent` prop. It replaces the adapter of the provider for this component only.

## External items

A navigation item with `external: true` opens a new tab. It does not use the adapter. It renders a plain `<a>` element with `target="_blank"` and `rel="noreferrer"`.

```tsx title="An external item"
{ id: 'docs', label: 'Documentation', href: 'https://example.com/docs', external: true }
```

## Your own links

- For a link that you write, use the link of your router.
- Do not put a ferry-ui component in a router link. Pass `href` to the component.
- For a link with the look of a button, use `asChild` on [Button](/docs/components/button).

```tsx title="A router link with the look of a button"
<Button asChild>
  <Link to="/projects/new">New project</Link>
</Button>
```

## Next steps

- Read the [LinkProvider](/docs/utilities/link-provider) page for the API and the `useLinkComponent()` hook.
- See the links in a full frame in the [App Shell](/docs/components/app-shell) page.
- Read [Composition](/docs/handbook/composition) to learn more about `asChild`.
