ReferenceComponent utilities tokens
Pass href and you're done. Roadie picks the right element, applies the
right target and rel defaults, and routes through the Link you give
RoadieProvider. Leave href off a button-shaped component and you get a
real <button> back. Every link-bearing component, listed under
Components, speaks the same vocabulary.
Pass next/link to RoadieProvider once at your app root, or any wrapper
that takes href and children. RoadieLinkProvider does the same on its
own, if you
place providers yourself.
Now every Roadie component that accepts href routes through Next's client
navigation by itself, keeping prefetch, scroll restoration, and view
transitions. Pass the Link at module scope, as above, because a new Link
reference on each render logs a dev warning.
The provider also marks each of those clicks as a navigation in flight, which
is what draws
the pending indicator on a
Navigator frame that is still waiting. Pass pendingIndicator={false} to
turn it off, and use usePendingNavigation for a
navigation Roadie never sees, such as your own router.push.
The same rules apply to every link-bearing component. The decision is pure and SSR-safe, with no hydration mismatches and no client-only checks.
| href shape | Renders as | Defaults applied |
|---|---|---|
| None | <button>, but see Components | None |
/events/123, ./local, #section | The configured Link, or <a> with no provider | None |
https://…, http://…, //… | <a> | target='_blank' and rel='noopener noreferrer' |
mailto:, tel:, sms: | <a> | None, so no target or rel |
Any internal href with download | <a> | None. A file isn't a route, so the provider's Link never prefetches it. |
javascript:, data:, vbscript:, blob:, file: | <a href='#'> | The href is refused, so the click does nothing, and a dev warning names it. |
Override per call with external (boolean), target, or rel. Pass
external={false} on an https://oztix.com.au/x URL to force internal
routing through the provider, and pass external on an internal redirect
path to open it in a new tab.
A download link skips the provider, so a router's base path isn't added to
it. If your app has one, include it in the href yourself.
Every component here accepts href. The ones with render also take
external, target, and rel, and render covers cases where href isn't
enough, such as custom elements or full render control.
| Component | Without href | With href | Escape hatch |
|---|---|---|---|
| Button and IconButton | <button> | Routed <a> | render |
| Card | <div> | Routed <a> | render |
| Card.Link | Needs href | Routed <a> | None |
| Breadcrumb.Link | <a> | Routed <a> | render |
| Carousel.TitleLink | <a> | Routed <a> | render |
| Tabs.Tab | <button> | Routed <a> | render |
| Toolbar.Button | <button> | Routed <a> | render |
| List.Item | <button> | Routed <a> | None, href only |
| Menu.Item | Menu item | Routed <a> | None, href only |
| Navigator items and tabs | <button> | Routed <a> | None, href only |
Row links in DataTable and RecordTable route the same way.
For a text link, use Link from
@oztix/roadie-components/link. It routes like the components above, so it
takes href, external, target, and rel, and its emphasis sets the
underline, as on its page.
import { Link } from '@oztix/roadie-components/link'<Link href='/events/123'>Ochre Kite Weekender</Link>
<Button href='/events/123'>View event</Button><Card href='/events/123'>{/* whole-card link */}</Card><Breadcrumb.Link href='/events'>Events</Breadcrumb.Link>
A card with other actions inside wraps its title in Card.Link instead, as
Card shows.
An https:// href renders an <a> with target='_blank' and
rel='noopener noreferrer'.
The href path covers the happy case. For full control over the rendered
element, these components accept the same render prop, in element,
component, or function form. The contract mirrors
Base UI's render prop.
Receive the default props and return any element. It's useful for state-aware rendering or attribute composition.
When you pass both href and render, render wins, and Roadie's routing is
off for that call. Button and IconButton log a one-time dev warning, so the
conflict can't ship by accident. Pick one.
Card, Breadcrumb.Link, and Carousel.TitleLink also take a legacy as
prop for polymorphism. It still works, but it's @deprecated as of v2.6 and
will be removed in v3.0.0, so migrate to render.
Tabs work as link tabs out of the box. Pass href on each Tabs.Tab and the
rendered anchor joins the tab list's roving tabindex group. Arrow keys still
move focus across mixed button and anchor tabs.
Pressing Enter on a focused link tab starts the browser's navigation at once.
If you derive value from controlled local state, you can see a brief
flicker between selection and route change. Derive value from the route
itself, such as with usePathname(), so the route is the source of truth.
Normalise it first, because tab matching is exact, so a trailing slash
selects nothing.
Roadie ships no analytics code. Tracking taxonomy is product-shaped (event
names, page sections, and vendor choices). The recommended pattern is a small
wrapper in your app that reads currentTarget.href or aria-label off the
rendered element, so a single <Tracked> works on top of every Roadie
action.
function useRoadieLink(): RoadieLinkComponent | null
Returns the Link passed to the nearest RoadieLinkProvider, or null when
no provider is mounted or its Link is null. Roadie's link-bearing
components build their href handling on it. Build your own the same way:
route through the configured Link when there is one, and render a plain
<a> when there isn't.
function usePendingNavigation(): { start: () => void; stop: () => void }
Reports a navigation Roadie can't see, such as your own router.push.
Roadie's own links already call start for you, so reach for this only when
you start the navigation yourself. Call start from the event handler that
kicks it off, because from a layout effect it schedules a render React
refuses.
| Field | Type | Description |
|---|---|---|
start | () => void | Marks a navigation as pending, which draws the pending indicator on a Navigator frame. |
stop | () => void | Ends it early. The route landing calls this for you, so call it yourself only when the navigation never happens. |
Both do nothing when no RoadieLinkProvider is mounted, or when it takes
pendingIndicator={false}.
LinkButton and LinkIconButton are still exported and still work, but new
code should use Button and IconButton with href. They're scheduled for
removal in v3.0.0.