HTML Links
html links anchor elements connect the web — crawlers, users, and assistive technology all anchor elements (<a href>) are
Introduction
Anchor elements (<a href>) are the web's native navigation primitive — crawlers, assistive tech, and browsers all depend on real links for discoverability and operability. Staff engineers distinguish links from button-styled divs: Airbnb room cards use <a href="/rooms/123"> in SSR HTML so Google indexes deep links; Stripe docs link externally with rel="noopener noreferrer" on target=_blank.
Business problem
Fake links (onclick on spans) break open-in-new-tab, copy-link, prefetch, and SEO. JavaScript-only navigation without href leaves orphan routes invisible to crawlers — a marketplace lost 30% organic traffic after SPA migration without link prerender.
- Conversion: Broken checkout deep links in email — missing https, wrong query params.
- A11y: "Click here" links fail WCAG 2.4.4 — BBC style guide mandates descriptive link text.
- Security: target=_blank without noopener — tab-nabbing on partner referral pages.
Why this feature exists
Tim Berners-Lee's core insight: hypertext links unify documents. href provides a universal affordance — activate with Enter, context menu, assistive tech link lists, and browser prefetch heuristics.
- History: name anchors deprecated for id fragments; download attribute added for file hints.
- Rejected: Java-only applets for navigation — failed accessibility and crawl.
- Modern: rel=noopener, prefetch, ping — HTML extends without breaking href contract.
Browser internals
HTMLAnchorElement exposes href, relList, and download. Click with unmodified primary button triggers navigation; modified clicks (ctrl, middle) delegate to browser UI. Parser tokenizes href early — invalid URLs may still resolve relative to document base.
- Prefetch: Speculation Rules and link rel=prefetch compete — respect data-saver.
- Fragment: #section scrolls after load — scroll-margin-top CSS affects anchor landing.
- Download: Cross-origin download attribute often ignored — Content-Disposition server-side.
Click <a href="/p"> → navigation decision (same-origin policy)relList.contains('noopener') → window.opener null on target=_blankhref="#" → scroll to top; avoid for buttons
Rendering workflow
Links are inline in layout — :hover/:focus styles trigger repaint. Underline via text-decoration-skip-ink reduces paint area. Prefetched href resources warm HTTP cache before click — Amazon product links prefetch on hover in some builds.
- LCP: Hero CTA link text is text paint — font loading applies.
- INP: SPA click handlers preventing default on fake links delay feedback — use real navigation where possible.
- CLS: Link icons loading without dimensions shift adjacent text.
Feature deep dive
Use <a> for navigation, <button> for actions. href must be meaningful URL or fragment. External links: rel="noopener noreferrer" + visual indicator. Email/tel use specialized schemes with validation.
- Absolute vs relative: Root-relative /path survives staging domains; protocol-relative // deprecated.
- aria-current: page on active nav link — don't rely on bold class alone.
- Skip links: First focusable
<a href="#main">— Google a11y baseline.
<nav aria-label="Primary"><a href="/" aria-current="page">Home</a><a href="/pricing">Pricing</a><a href="https://docs.stripe.com" rel="noopener noreferrer">Docs</a></nav><main id="main">…</main>
Accessibility analysis
Link purpose must be clear from text or aria-label — not "read more" alone. Screen readers browse links rotor; duplicate "Learn more" fifty times is useless. Focus indicator required — outline removal fails 2.4.7.
- Icon-only: aria-label or visible text — Instagram share icon needs name.
- New window: Warn when target=_blank — "(opens in new tab)" in visible or aria-label.
- Redundant: Don't nest interactive elements — no button inside link.
SEO impact
Internal linking distributes PageRank and discovery — Amazon footer category links shape crawl graph. href on rendered HTML required; Googlebot may not fire click handlers. rel=nofollow on paid/sponsored per guidelines.
- Crawlable: href in SSR HTML — not data-href awaiting JS.
- Canonical: Link to canonical URL in nav — avoid duplicate paths.
- Sitelinks: Clear nav anchors help Google infer site structure.
Security considerations
javascript: URLs in href are XSS vectors — sanitize CMS output. Referrer leakage on external links — use noreferrer on sensitive pages. Phishing sites mimic href display text vs actual URL — teach users to inspect status bar.
- Tabnabbing: window.opener access without noopener.
- Open redirect: /out?url= user-controlled href — validate allowlist server-side.
- CSRF: GET links that mutate state — use POST forms, not destructive href.
Performance impact
Prefetch/prerender of in-viewport links trades bandwidth for faster navigation — Shopify admin prefetches likely next routes. Too many prefetch hints compete with LCP image download on mobile.
- HTTP/2: Multiplexed small HTML navigations — still full document parse cost.
- SPA: Client routing avoids reload — preserve link semantics with href for SEO prerender.
- INP: Instant visual feedback on :active — 80ms perceived win on mobile.
Real production example
BBC article templates use descriptive link text in body copy, related-story links with full headline as anchor text, and external links marked in copy style guide. Speculation Rules API added in head for top stories only.
- Analytics: ping attribute or beacon — don't block navigation on sendBeacon fail.
- International: hreflang alternates as link in head, not body anchors.
- Broken link CI: linkinator on built HTML weekly.
<a href="/article/climate-report"hreflang="en">UK climate report 2024: full findings</a>
Enterprise usage
Enterprise portals enforce link policy: no empty href, no javascript:, descriptive text lint in CMS, automated external link review for partner domains. Design system Link component always renders anchor with href.
- PDF exports: Absolute URLs in print HTML — relative breaks offline.
- Email: Full URL visible for trust — not hidden behind shortener only.
- Legal: Sponsored links need rel=sponsored + disclosure adjacent.
Common production failures
Marketplace SPA replaced product card anchors with div onClick — organic listings dropped from index over 8 weeks. Travel site target=_blank on all external links leaked session referrer tokens to analytics partners.
- Empty href: Keyboard users activate to page reload — support tickets.
- Hash-only: Marketing used href="#" for modal triggers — broke middle-click.
- Mobile: tel: link without proper formatting failed on iOS Safari dialer.
Architecture review questions
- Does every navigational control use an anchor with a valid href?
- Is link text descriptive without relying on surrounding context alone?
- Are external target=_blank links paired with rel=noopener noreferrer?
- Can crawlers reach this URL from static href in HTML without JavaScript?
- Are destructive actions avoided via GET links?
- Do icon-only links have accessible names?
Hands-on project
Refactor a card grid from div-click navigation to semantic anchors; add skip link, aria-current on nav, and run linkinator + axe on built page.
- Deliverable: Middle-click opens product in new tab works.
- Verify: View crawled HTML — href present in SSR.
- Stretch: Speculation Rules for top 3 likely next pages.
Interview questions
When is a button more correct than an anchor?(Advanced)
When activation performs an in-page action without URL change: submit, open modal, expand accordion, add to cart via API. Buttons prevent accidental navigation and communicate role to AT. Anchors for href navigation — even in SPAs use href + enhance.
Follow-up: How do SPAs keep SEO with client routing?
Explain tabnabbing and the noopener fix.(Advanced)
target=_blank gives new page window.opener reference to your page. Attacker can redirect opener via location. rel=noopener severs opener; noreferrer also strips Referer header. Always on third-party untrusted targets.
Follow-up: Doesnoopener affect window.name?
How do prefetch and prerender differ in impact on Core Web Vitals?(Advanced)
prefetch loads resource low priority for likely next navigation; prerender builds full page — expensive. Over-prerender hurts LCP bandwidth on current page. Use Speculation Rules with eagerness conservative on mobile data.
Follow-up: Same-origin prerender constraints?
Try it yourself
Edit the HTML, CSS, or JS panels — the preview updates as you type.
Try it yourself
Summary
Anchor elements connect the web — crawlers, users, and assistive technology all require valid href semantics. Staff patterns from BBC and Airbnb keep links in SSR HTML, descriptive, and secured with rel attributes on external targets.