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

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