HTML <a> reference Jump to this section

Common attributes Jump to this section

An <a> (anchor) element creates a hyperlink to web pages, files, email addresses, locations in the same page, or anything else a URL can address.

<a href="https://example.com">Visit Example</a>

href Jump to this section

The hyperlink reference - the URL the link points to. This is the most important attribute and defines where the link navigates.

Common URL types:

  • Absolute: https://example.com
  • Relative: /about, ../page.html
  • Anchor: #section-id
  • Email: mailto:user@example.com
  • Phone: tel:+1234567890
  • JavaScript: javascript:void(0) (avoid when possible)
<!-- External link -->
<a href="https://example.com">External Site</a>

<!-- Relative link -->
<a href="/about">About Page</a>

<!-- Page anchor -->
<a href="#features">Jump to Features</a>

<!-- Email link -->
<a href="mailto:hello@example.com">Email Us</a>

<!-- Phone link -->
<a href="tel:+1234567890">Call Us</a>

<!-- File download -->
<a href="/files/document.pdf">Download PDF</a>

target Jump to this section

Specifies where to open the linked document.

Values:

  • _self (default): Opens in the same browsing context
  • _blank: Opens in a new tab or window
  • _parent: Opens in the parent frame
  • _top: Opens in the top-most frame
<a href="https://example.com" 
   target="_blank" 
   rel="noopener noreferrer">
    Open in New Tab
</a>

Security note: When using target="_blank", always include rel="noopener noreferrer" to prevent security vulnerabilities and performance issues.

rel Jump to this section

Specifies the relationship between the current document and the linked document. Important for security, SEO, and functionality.

Common values:

  • noopener: Prevents the new page from accessing window.opener
  • noreferrer: Prevents the browser from sending the referrer header
  • nofollow: Tells search engines not to follow this link
  • sponsored: Marks the link as sponsored content
  • ugc: User-generated content (like comments)
  • external: Indicates an external link
  • help: Links to help documentation
  • prev / next: Previous/next in a sequence
<!-- External link (security) -->
<a href="https://example.com" 
   target="_blank" 
   rel="noopener noreferrer">
    External Link
</a>

<!-- Sponsored link (SEO) -->
<a href="https://sponsor.com" rel="sponsored nofollow">
    Sponsored Link
</a>

<!-- User content link (SEO) -->
<a href="https://user-site.com" rel="ugc nofollow">
    User's Website
</a>

<!-- Pagination -->
<a href="/page/2" rel="next">Next Page</a>

download Jump to this section

Prompts the user to download the linked resource instead of navigating to it. The attribute value becomes the suggested filename.

<a href="/files/report.pdf" download="monthly-report.pdf">
    Download Report
</a>

<!-- Browser suggests filename --> <a href="/files/data.csv" download> Download CSV </a>

Note: Download only works for same-origin URLs or blob/data URLs. Cross-origin files require appropriate CORS headers.

hreflang Jump to this section

Indicates the language of the linked document. Helpful for search engines and browsers.

<a href="/es/about" hreflang="es">Acerca de</a>
<a href="/fr/contact" hreflang="fr">Contact</a>
<a href="/de/home" hreflang="de">Startseite</a>

type Jump to this section

Specifies the MIME type of the linked resource. Helps browsers handle the link appropriately.

<a href="/document.pdf" type="application/pdf">PDF Document</a>
<a href="/video.mp4" type="video/mp4">Watch Video</a>
<a href="/feed.xml" type="application/rss+xml">RSS Feed</a>

ping Jump to this section

Specifies URLs to be notified when the user follows the link. Used for tracking (privacy-conscious alternative to JavaScript tracking).

<a href="https://example.com" 
   ping="https://analytics.example.com/track">
    Tracked Link
</a>

Privacy note: Some browsers may ignore this attribute based on user privacy settings.

referrerpolicy Jump to this section

Controls how much referrer information is sent when following the link.

Values:

  • no-referrer: Never send referrer
  • no-referrer-when-downgrade: Don't send when going from HTTPS to HTTP
  • origin: Send only the origin (domain)
  • origin-when-cross-origin: Full URL for same-origin, origin only for cross-origin
  • same-origin: Send referrer only for same-origin requests
  • strict-origin: Like origin, but not on HTTPS to HTTP
  • strict-origin-when-cross-origin (default): Full URL same-origin, origin cross-origin
  • unsafe-url: Always send full URL (not recommended)
<a href="https://example.com" 
   referrerpolicy="no-referrer">
    Private Link
</a>

<a href="https://example.com" 
   referrerpolicy="origin">
    Send Origin Only
</a>

Accessibility attributes Jump to this section

aria-label Jump to this section

Provides an accessible label when the link text alone isn't descriptive enough.

<!-- Icon-only link -->
<a href="/settings" aria-label="Account Settings">
    ⚙️
</a>

<!-- Ambiguous text -->
<a href="/article/1" aria-label="Read more about accessibility">
    Read more
</a>

aria-describedby Jump to this section

References additional descriptive text by its id to provide more context.

<a href="/premium" aria-describedby="premium-description">
    Upgrade to Premium
</a>
<span id="premium-description">
    Get unlimited access for $9.99/month
</span>

aria-current Jump to this section

Indicates which link represents the current page/location. Important for navigation.

Values: page, step, location, date, time, true, false

<nav>
    <a href="/" aria-current="page">Home</a>
    <a href="/about">About</a>
    <a href="/contact">Contact</a>
</nav>

aria-disabled Jump to this section

Indicates the link is disabled. Unlike buttons, links don't have a native disabled state.

<a href="#" aria-disabled="true" 
   style="pointer-events: none; opacity: 0.5;">
    Unavailable Link
</a>

tabindex Jump to this section

Controls keyboard focus order. Links are naturally focusable, so this is rarely needed.

<!-- Remove from tab order -->
<a href="javascript:void(0)" tabindex="-1">Not Keyboard Accessible</a>

<!-- Custom tab order (avoid if possible) -->
<a href="javascript:void(0)" tabindex="1">First Tab Stop</a>

Other common attributes Jump to this section

id Jump to this section

Unique identifier for the link. Can be used as a target for anchor navigation.

<a href="#section-1">Go to Section 1</a>

<!-- Later in the document -->
<h2 id="section-1">Section 1</h2>

class Jump to this section

Assigns CSS class names for styling or JavaScript selection.

<a href="/docs" class="button button-primary">
    View Documentation
</a>

title Jump to this section

Provides additional information as a tooltip on hover. Not accessible to keyboard-only users or mobile, so don't rely on it for critical information.

<a href="/help" title="Get help and support">
    Help
</a>

data-* attributes Jump to this section

Custom attributes for storing application-specific data on the link.

<a href="/product/123" 
   data-product-id="123" 
   data-category="electronics">
    View Product
</a>

<script>
  const link = document.querySelector('a');
  const productId = link.dataset.productId; // "123"
  const category = link.dataset.category; // "electronics"
</script>

style Jump to this section

Inline CSS styles. Generally prefer external stylesheets or classes.

<a href="/important" 
   style="color: red; font-weight: bold;">
    Important Link
</a>

Link to specific sections within the same page.

<a href="#section-id">Jump to Section</a>

<!-- Target element --> <section id="section-id"> <h2>Section Title</h2> </section>

Open the user's email client with pre-filled information.

<!-- Basic email -->
<a href="mailto:hello@example.com">Email Us</a>

<!-- With subject -->
<a href="mailto:support@example.com?subject=Help Request">
    Support
</a>

<!-- With subject and body -->
<a href="mailto:info@example.com?subject=Inquiry&body=Hello,">
    Contact
</a>

<!-- Multiple recipients -->
<a href="mailto:one@example.com,two@example.com">
    Email Multiple
</a>

<!-- CC and BCC -->
<a href="mailto:to@example.com?cc=copy@example.com&bcc=hidden@example.com">
    Email with CC/BCC
</a>

Initiate phone calls on devices with calling capability.

<!-- Basic phone link -->
<a href="tel:+1234567890">Call Us</a>

<!-- With extension -->
<a href="tel:+1234567890,,,123">Call (ext. 123)</a>

<!-- International format -->
<a href="tel:+44-20-1234-5678">Call UK Office</a>

Open SMS/messaging app with pre-filled content.

<!-- Basic SMS -->
<a href="sms:+1234567890">Send SMS</a>

<!-- With message body -->
<a href="sms:+1234567890?body=Hello!">Text Us</a>

<!-- iOS uses different syntax for body -->
<a href="sms:+1234567890&body=Hello!">Text Us (iOS)</a>
<!-- WhatsApp -->
<a href="https://wa.me/1234567890">Chat on WhatsApp</a>

<!-- Skype -->
<a href="skype:username?call">Call on Skype</a>

<!-- FaceTime -->
<a href="facetime:email@example.com">FaceTime</a>

<!-- Maps -->
<a href="https://maps.google.com/?q=New+York">View on Maps</a>

<!-- App Store / Play Store -->
<a href="https://apps.apple.com/app/id123456">Download iOS App</a>
<a href="https://play.google.com/store/apps/details?id=com.app">
    Download Android App
</a>

Styling basics Jump to this section

Links are highly customizable with CSS. Control appearance across different states (link, visited, hover, active, focus) to create engaging and accessible interfaces.

Links have several states that should be styled in this order: :link, :visited, :hover, :focus, :active (remember: LoVe HAte).

/* Unvisited link */
a:link {
    color: #3b82f6;
}

/* Visited link */
a:visited {
    color: #8b5cf6;
}

/* Mouse hover */
a:hover {
    color: #2563eb;
    text-decoration: none;
}

/* Keyboard focus */
a:focus {
    outline: 2px solid #93c5fd;
    outline-offset: 2px;
}

/* Active (being clicked) */
a:active {
    color: #1e40af;
}
.link-basic {
    color: #3b82f6;
    text-decoration: underline;
}

.link-basic:hover { color: #2563eb; }

No underline (with hover effect) Jump to this section

.link-hover-underline {
    color: #3b82f6;
    text-decoration: none;
    transition: color 0.2s;
}

.link-hover-underline:hover { text-decoration: underline; }

.link-button {
    display: inline-block;
    padding: 10px 20px;
    background: #3b82f6;
    color: white;
    text-decoration: none;
    border-radius: 6px;
    font-weight: 500;
    transition: background 0.2s;
}

.link-button:hover { background: #2563eb; }

.link-outlined {
    display: inline-block;
    padding: 10px 20px;
    border: 2px solid #3b82f6;
    color: #3b82f6;
    text-decoration: none;
    border-radius: 6px;
    font-weight: 500;
    transition: all 0.2s;
}

.link-outlined:hover { background: #3b82f6; color: white; }

Underline animation Jump to this section

.link-animated {
    position: relative;
    color: #3b82f6;
    text-decoration: none;
    padding-bottom: 2px;
}

.link-animated::after { content: ''; position: absolute; bottom: 0; left: 0; width: 0; height: 2px; background: #3b82f6; transition: width 0.3s; }

.link-animated:hover::after { width: 100%; }

.link-arrow {
    color: #3b82f6;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: gap 0.2s;
}

.link-arrow:hover { gap: 10px; }

New
.link-badge {
    display: inline-block;
    padding: 4px 10px;
    background: #dbeafe;
    color: #1e40af;
    text-decoration: none;
    border-radius: 12px;
    font-size: 13px;
    font-weight: 500;
    transition: background 0.2s;
}

.link-badge:hover { background: #bfdbfe; }

.link-card {
    display: block;
    padding: 20px;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    text-decoration: none;
    color: inherit;
    transition: all 0.2s;
}

.link-card:hover { border-color: #3b82f6; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); }

<a href="#" class="link-icon">
    <svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 
              d="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
    </svg>
    Add item
</a>
.link-icon {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: #3b82f6;
    text-decoration: none;
    transition: color 0.2s;
}

.link-icon:hover { color: #2563eb; }

.link-icon svg { width: 20px; height: 20px; }

<a href="https://example.com" target="_blank" rel="noopener" class="link-external">
    External link
    <svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 
              d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
    </svg>
</a>
.link-external {
    color: #3b82f6;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

/* Alternative with ::after pseudo-element */ .link-external::after { content: ''; display: inline-block; width: 14px; height: 14px; background-image: url('external-icon.svg'); }

<a href="/file.pdf" download class="link-download">
    <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 
              d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
    </svg>
    Download
</a>
.link-download {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    background: #10b981;
    color: white;
    text-decoration: none;
    border-radius: 6px;
    font-weight: 500;
    transition: background 0.2s;
}

.link-download:hover { background: #059669; }

.link-disabled {
    color: #9ca3af;
    text-decoration: none;
    cursor: not-allowed;
    pointer-events: none;
    opacity: 0.6;
}

/* Or with attribute selector */ a[aria-disabled="true"] { color: #9ca3af; cursor: not-allowed; pointer-events: none; }

.nav-link {
    color: #6b7280;
    text-decoration: none;
    padding-bottom: 4px;
    border-bottom: 2px solid transparent;
    transition: color 0.2s;
}

.nav-link:hover { color: #374151; }

.nav-link[aria-current="page"] { color: #3b82f6; font-weight: 600; border-bottom-color: #3b82f6; }

Focus styles (accessibility) Jump to this section

Always provide clear focus indicators for keyboard navigation.

.link-focus {
    color: #3b82f6;
    text-decoration: none;
    padding: 8px 12px;
    border-radius: 4px;
    transition: all 0.2s;
}

.link-focus:focus { outline: 2px solid #93c5fd; outline-offset: 2px; }

/* Visible focus only for keyboard users */ .link-focus:focus-visible { outline: 2px solid #93c5fd; outline-offset: 2px; }

.link-focus:focus:not(:focus-visible) { outline: none; }

.social-link {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    text-decoration: none;
    transition: transform 0.2s;
}

.social-link:hover { transform: scale(1.1); }

.social-link.twitter { background: #1da1f2; } .social-link.linkedin { background: #0077b5; } .social-link.github { background: #333; }

JavaScript patterns Jump to this section

Links can be enhanced with JavaScript for tracking, dynamic behavior, smooth scrolling, and interactive features.

Prevent default navigation Jump to this section

Prevent the link from navigating and handle the action with JavaScript.

const link = document.getElementById('js-prevent');
const output = document.getElementById('prevent-output');
link.addEventListener('click', (e) => {
    e.preventDefault(); // Prevent navigation
    output.textContent = 'Navigation prevented!';
});

Smooth scroll to anchor Jump to this section

Smoothly scroll to page sections instead of jumping.

const smoothLinks = document.querySelectorAll('a[href^="#"]');
smoothLinks.forEach(link => {
    link.addEventListener('click', (e) => {
        e.preventDefault();
        const targetId = link.getAttribute('href');
        const target = document.querySelector(targetId);
        if (target) {
            target.scrollIntoView({
                behavior: 'smooth',
                block: 'start'
            });
        }
    });
});
// CSS alternative
html {
    scroll-behavior: smooth;
}

Confirm before navigation Jump to this section

Show a confirmation dialog for critical actions.

const dangerLink = document.getElementById('js-confirm');
dangerLink.addEventListener('click', (e) => {
    const confirmed = confirm(
        'Are you sure you want to delete your account?'
    );
    if (!confirmed) {
        e.preventDefault();
    }
    // If confirmed, navigation proceeds normally
});

Track when users click external links.

const trackedLinks = document.querySelectorAll('.js-track');
const trackOutput = document.getElementById('track-output');
trackedLinks.forEach(link => {
    link.addEventListener('click', (e) => {
        const url = link.href;
        // Send to analytics
        trackOutput.textContent = `Tracked: ${url}`;
        // Example: Send to analytics service
        // analytics.track('Link Click', { url: url });
        // Don't prevent - let navigation happen
    });
});

Add a "Copy link" button functionality.

<div style="display:flex;align-items:center;gap:12px;">
    <a href="https://example.com/article" id="shareable-link">Article link</a>
    <button id="copy-link-btn">Copy</button>
</div>
<div id="copy-status"></div>
const link = document.getElementById('shareable-link');
const copyBtn = document.getElementById('copy-link-btn');
const status = document.getElementById('copy-status');
copyBtn.addEventListener('click', async () => {
    const url = link.href;
    try {
        await navigator.clipboard.writeText(url);
        status.textContent = 'Link copied!';
        setTimeout(() => {
            status.textContent = '';
        }, 2000);
    } catch (err) {
        status.textContent = 'Failed to copy';
        status.style.color = '#dc2626';
    }
});

Automatically open external links in new tabs.

// Select all links in content
const links = document.querySelectorAll('#content-area a');
links.forEach(link => {
    const url = new URL(link.href, window.location.origin);
    // Check if external
    if (url.origin !== window.location.origin) {
        link.setAttribute('target', '_blank');
        link.setAttribute('rel', 'noopener noreferrer');
    }
});

Create links dynamically from data.

const container = document.getElementById('link-container');
const button = document.getElementById('generate-links');
const pages = [
    { title: 'Home', url: '/' },
    { title: 'About', url: '/about' },
    { title: 'Blog', url: '/blog' },
    { title: 'Contact', url: '/contact' }
];
button.addEventListener('click', () => {
    container.innerHTML = '';
    pages.forEach(page => {
        const link = document.createElement('a');
        link.href = page.url;
        link.textContent = page.title;
        link.style.color = '#3b82f6';
        link.style.textDecoration = 'none';
        container.appendChild(link);
    });
});

Lazy load on click Jump to this section

Load content when a link is clicked instead of navigating.

const loadLink = document.getElementById('load-content');
const contentDiv = document.getElementById('loaded-content');
loadLink.addEventListener('click', async (e) => {
    e.preventDefault();
    loadLink.textContent = 'Loading...';
    try {
        const response = await fetch(loadLink.href);
        const data = await response.text();

contentDiv.innerHTML = data; contentDiv.style.display = 'block'; loadLink.textContent = 'Reload content'; } catch (err) { contentDiv.textContent = 'Failed to load content'; contentDiv.style.display = 'block'; loadLink.textContent = 'Try again'; } });

Toggle active state Jump to this section

Toggle active state on navigation links.

const navLinks = document.querySelectorAll('#nav-menu a');
navLinks.forEach(link => {
    link.addEventListener('click', (e) => {
        e.preventDefault();
        // Remove active from all
        navLinks.forEach(l => {
            l.style.color = '#6b7280';
            l.style.fontWeight = '400';
            l.style.background = 'transparent';
        });
        // Add active to clicked
        link.style.color = '#3b82f6';
        link.style.fontWeight = '600';
        link.style.background = '#eff6ff';
    });
});

Prefetch on hover Jump to this section

Prefetch page content when hovering over links for faster navigation.

const prefetchLinks = document.querySelectorAll('.prefetch-link');
const status = document.getElementById('prefetch-status');
prefetchLinks.forEach(link => {
    let prefetched = false;
    link.addEventListener('mouseenter', () => {
        if (prefetched) return;
        const url = link.href;
        status.textContent = 'Prefetching...';
        // Create prefetch link element
        const prefetchLink = document.createElement('link');
        prefetchLink.rel = 'prefetch';
        prefetchLink.href = url;
        document.head.appendChild(prefetchLink);
        prefetched = true;
        status.textContent = 'Prefetched!';
        setTimeout(() => {
            status.textContent = '';
        }, 2000);
    });
});

Tooltip on hover Jump to this section

Show custom tooltip when hovering over links.

Hover for tooltip
<div style="position:relative;display:inline-block;">
    <a href="#" id="tooltip-link">Hover for tooltip</a>
    <div id="custom-tooltip" style="position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);padding:6px 12px;background:#1f2937;color:white;border-radius:6px;font-size:13px;white-space:nowrap;display:none;pointer-events:none;">
        Click to learn more
        <div style="position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:#1f2937;"></div>
    </div>
</div>
const link = document.getElementById('tooltip-link');
const tooltip = document.getElementById('custom-tooltip');
link.addEventListener('mouseenter', () => {
    tooltip.style.display = 'block';
});
link.addEventListener('mouseleave', () => {
    tooltip.style.display = 'none';
});
// Alternative: Use data attributes
link.setAttribute('data-tooltip', 'Click to learn more');

Generate breadcrumb links from URL path.

function generateBreadcrumbs(path) {
    const container = document.getElementById('breadcrumbs');
    const parts = path.split('/').filter(Boolean);
    let currentPath = '';
    const breadcrumbs = parts.map((part, index) => {
        currentPath += '/' + part;
        const isLast = index === parts.length - 1;
        if (isLast) {
            return `<span style="color:#6b7280;">${part}</span>`;
        } else {
            return `<a href="${currentPath}" 
                       style="color:#3b82f6;text-decoration:none;">
                        ${part}
                    </a>`;
        }
    });
    container.innerHTML = breadcrumbs.join('  /  ');
}

Download with progress Jump to this section

Show download progress for file links.

<a href="#" id="download-link">Download file</a>
<div id="download-progress" style="display:none;">
    <div style="height:4px;background:#e5e7eb;border-radius:2px;overflow:hidden;">
        <div id="progress-bar" style="height:100%;width:0%;background:#3b82f6;"></div>
    </div>
    <div id="progress-text">0%</div>
</div>
const downloadLink = document.getElementById('download-link');
const progressDiv = document.getElementById('download-progress');
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');
downloadLink.addEventListener('click', async (e) => {
    e.preventDefault();
    progressDiv.style.display = 'block';
    // Simulate download progress
    for (let i = 0; i <= 100; i += 10) {
        await new Promise(resolve => setTimeout(resolve, 200));
        progressBar.style.width = i + '%';
        progressText.textContent = i + '%';
    }
    progressText.textContent = 'Complete!';
    setTimeout(() => {
        progressDiv.style.display = 'none';
        progressBar.style.width = '0%';
    }, 2000);
});