oxc-project/oxc · warning · OxcDiagnostic
Do not use `<a>` elements to navigate between Next.js pages.
Error message
Do not use `<a>` elements to navigate between Next.js pages.
What it means
Warning from oxlint rule `nextjs/no-html-link-for-pages`. Internal links rendered as plain `<a href="/...">` force a full document reload, losing client-side navigation, prefetching, and scroll restoration. The rule flags anchor tags whose string `href` targets an internal route.
Source
Thrown at crates/oxc_linter/src/rules/nextjs/no_html_link_for_pages.rs:12
use oxc_ast::{
AstKind,
ast::{JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXElementName},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{AstNode, context::LintContext, rule::Rule};
fn no_html_link_for_pages_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Do not use `<a>` elements to navigate between Next.js pages.")
.with_help("Use `<Link />` from `next/link` instead for internal navigation. See https://nextjs.org/docs/messages/no-html-link-for-pages")
.with_label(span.label("Replace with `<Link>` from `next/link`"))
}
#[derive(Debug, Default, Clone)]
pub struct NoHtmlLinkForPages;
declare_oxc_lint!(
/// ### What it does
///
/// Prevents the usage of `<a>` elements to navigate between Next.js pages.
///
/// ### Why is this bad?
///
/// Using `<a>` elements for internal navigation in Next.js applications can cause:
/// - Full page reloads instead of client-side navigation
/// - Loss of application state
/// - Slower navigation performanceView on GitHub (pinned to e1e7af627c)
Solutions
- `import Link from 'next/link'` and use `<Link href="/about">About</Link>`.
- Keep `<a>` only for external URLs (full `https://...`) or non-navigation anchors (`#`, mailto, downloads).
Example fix
// before <a href="/about">About</a> // after import Link from 'next/link'; <Link href="/about">About</Link>
Defensive patterns
Strategy: validation
Validate before calling
function isInternalHref(href: string): boolean {
return href.startsWith('/') && !href.startsWith('//');
}
// review flagged: rg -n '<a [^>]*href="/"?' -g '*.tsx' src Type guard
function isInternalHref(href: string): boolean {
return href.startsWith('/') && !href.startsWith('//');
} Prevention
- Use `<Link>` by default for any href starting with `/`.
- Reserve `<a>` for external URLs, `#anchors`, mailto, and file downloads.
- Keep the nextjs oxlint plugin on so reviewers do not have to eyeball every anchor.
When it happens
Trigger: A JSX `<a>` element whose `href` is a string literal starting with `/` (no scheme or host), i.e. an app-internal URL.
Common situations: Migrating server-rendered HTML with hard-coded links; linking between routes in landing pages. Note: upstream this rule is deprecated since Next 13 (Link no longer needs an `<a>` child), but plain internal anchors are still worth converting.
Related errors
- A font-display parameter is missing (adding `&display=option
- `{font_display_value}` is not a recommended font-display val
- `rel="preconnect"` is missing from Google Font.
- Using `<img>` could result in slower LCP and higher bandwidt
- Custom fonts not added in `pages/_document.js` will only loa
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/027f0a4c94f876fe.
Report an issue: GitHub.