Link Component
The Link component provides SPA-style navigation without page reloads. It renders a standard <a> element and automatically handles internal navigation via history.pushState, while allowing normal browser behavior for external links.
Setup
Import Link from metaowl and register it in your component's static components:
import { Component } from '@odoo/owl'
import { Link } from 'metaowl'
export class MyNav extends Component {
static template = 'MyNav'
static components = { Link }
setup() {
this.linkClass = (href) => {
const base = 'block px-3 py-2 rounded-md text-sm'
const active = 'bg-gray-100 text-gray-900'
const inactive = 'text-gray-600 hover:bg-gray-100'
const isActive = window.location.pathname === href
return base + ' ' + (isActive ? active : inactive)
}
}
}
Basic Usage
Prop values are OWL expressions — wrap static strings in extra quotes, or pass method calls:
<!-- Internal link -->
<Link to="'/about'">About Us</Link>
<!-- Dynamic target from loop -->
<Link to="item.href"><t t-esc="item.label"/></Link>
<!-- Computed class via method -->
<Link to="item.href" class="linkClass(item.href)">
<t t-esc="item.label"/>
</Link>
<!-- External link - opens normally (auto-detected, no SPA) -->
<Link to="'https://github.com/odoo/owl'" target="'_blank'">
OWL Framework
</Link>
<!-- External with dynamic target, closing sidebar on click -->
<Link
to="link.href"
target="link.external ? '_blank' : undefined"
t-on-click="props.onClose"
class="linkClass(link.href)"
activeClass="'text-yellow-500'"
>
<span t-esc="link.label"/>
</Link>
Props
Any additional attribute (id, style, aria-*, data-*, etc.) is forwarded directly to the rendered <a> element.
| Prop |
Type |
Required |
Description |
to |
string |
Yes |
Target URL (internal path or external URL) |
class |
string |
No |
CSS classes for the anchor element |
activeClass |
string |
No |
Extra CSS classes added when the link is active (current route matches to) |
target |
string |
No |
Target window (_blank, _self, etc.) |
rel |
string |
No |
Relationship attribute (auto-set to noopener noreferrer for external _blank links) |
download |
string | boolean |
No |
Download attribute for file downloads |
hreflang |
string |
No |
Language of the linked resource |
type |
string |
No |
MIME type hint |
ping |
string |
No |
Space-separated URLs to ping on click |
referrerpolicy |
string |
No |
Referrer policy override |
media |
string |
No |
Media query hint |
External Link Detection
The component automatically detects external links and performs normal navigation. URLs starting with https:// or http://, as well as special protocols like mailto:, tel:, and ftp: are treated as external and bypass the SPA router.
<!-- These are automatically treated as external -->
<Link to="'https://example.com'">External site</Link>
<Link to="'mailto:hello@example.com'">Send email</Link>
<Link to="'tel:+1234567890'">Call us</Link>
<!-- Internal links use SPA navigation -->
<Link to="'/about'">About Us</Link>
<Link to="'/docs/getting-started'">Getting Started</Link>
Programmatic Navigation
Use navigateTo() for programmatic navigation in JavaScript:
import { navigateTo } from 'metaowl'
// Navigate to a new route
await navigateTo('/dashboard')
// Replace current history entry (no back button)
await navigateTo('/login', { replace: true })
Router API
You can also use the router object directly for more control:
import { router, navigateTo } from 'metaowl'
// Navigation
router.push('/path') // Navigate to path
router.replace('/path') // Replace current history entry
router.navigateTo('/path') // SPA navigation
router.back() // Go back
router.forward() // Go forward
router.go(-2) // Go 2 steps back