javascript in href: Best practices for anchors and inline JS
A comprehensive guide to understanding and safely handling javascript in href. Learn why inline JS is discouraged, explore accessible alternatives, and implement unobtrusive event handling with progressive enhancement across modern browsers in 2026.

javascript in href embeds JavaScript code directly in an anchor's href attribute to trigger actions. This pattern is widely discouraged due to accessibility, security, and maintainability concerns. Prefer real URLs for navigation and attach behavior with addEventListener in separate JavaScript files. If navigation must be prevented, use href="#" with a defensive preventDefault in your script.
What 'javascript in href' means and why it matters
The pattern 'javascript in href' uses an inline JavaScript URL inside the href attribute of an anchor tag to run code when the link is activated. While it might seem convenient, it bypasses a link's semantic purpose and can degrade accessibility for screen readers, block navigation for keyboard users, and complicate content security and testing. In practice, prefer real URLs or progressive enhancement with event listeners.
<a href="javascript:void(0)" onclick="doThing()">Run</a>Why this matters: inline JavaScript ties behavior to markup, making behavior harder to reason about and harder to test in isolation. It also makes automated accessibility checks fail and can expose attackers to XSS vectors if dynamic code is not carefully sanitized. A modern approach keeps markup semantic and behavior in JavaScript, not in HTML.
Accessibility and security risks of javascript in href
Anchors should represent navigable destinations. When href contains JavaScript, keyboard focus, screen readers, and search engines can misinterpret the element, leading to poor UX and inconsistent results. Additionally, inline scripts are a common vector for cross-site scripting (XSS) if user input is interpolated or not sanitized. The safe practice is to remove inline JS and rely on event listeners attached after the DOM is loaded.
<a href="#" id="safeLink">Click me</a>
<script>
const el = document.getElementById('safeLink');
el.addEventListener('click', (e) => {
e.preventDefault();
doSomething();
});
</script>This pattern preserves semantics: the link can still navigate (if you choose a real URL) or can be a button, while the behavior is defined in JavaScript code separate from the HTML.
Modern alternatives: unobtrusive JavaScript and progressive enhancement
A robust approach replaces javascript: URLs with a real href and unobtrusive event handlers. This improves accessibility, SEO, and security while making maintenance easier. Use data attributes to store identifiers and attach handlers in a single script that runs on DOMContentLoaded.
<a href="/target-page" class="action-link" data-action="openModal">Open</a>// attachments: lightweight, centralized behavior
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('a.action-link').forEach(a => {
a.addEventListener('click', (ev) => {
ev.preventDefault();
const action = a.dataset.action;
if (action === 'openModal') {
openModal();
}
});
});
});If no JavaScript is available, the link will navigate to the real URL (as defined by href), preserving accessibility. This is the essence of progressive enhancement.
Scanning and refactoring existing codebases
If you inherit a project with many javascript: href usages, start with a targeted audit. Use static analysis or search tools to locate occurrences, then refactor in batches. A typical pattern is to replace href="javascript:..." with href="#" or with a valid URL and move the logic into a script file.
# example: find files containing javascript: href patterns
rg -n --glob 'src/**' 'href="javascript:'// targeted refactor example
const links = document.querySelectorAll('a[href^="javascript:"]');
links.forEach(l => {
l.removeAttribute('href'); // safe default, or set to a real URL
l.addEventListener('click', (e) => {
e.preventDefault();
// migrate to function call
doThing();
});
});Patterns, pitfalls, and best practices
Best practice: avoid inline JS entirely; prefer real URLs and a small, centralized script that handles interactions. When you must use anchors for actions, ensure that keyboard users can activate the action and that screen readers announce the intent. Consider using role="button" only when the anchor is not a navigable link and provide a real URL otherwise.
<a href="#" class="cta" aria-label="Open dialog" data-action="openDialog">Open dialog</a>document.querySelectorAll('a[data-action="openDialog"]').forEach(el => {
el.addEventListener('click', (e) => {
e.preventDefault();
openDialog();
});
});Frameworks and real-world patterns
Modern frameworks discourage javascript: href in favor of declarative bindings. In React/Vue, attach handlers in the component lifecycle and never put executable code in href attributes. For server-side rendering, maintain semantic anchors and enhance them with client-side scripts for behavior. This keeps code maintainable and secure across devices and browsers in 2026.
// React example - unobtrusive click handler
function MyLink() {
return <a href={targetUrl} onClick={(e) => { /* logic */ e.preventDefault(); openModal(); }}>Open</a>;
}Steps
Estimated time: 60-120 minutes
- 1
Audit current usage
Scan the codebase for any href attributes containing javascript: and note where they occur most frequently. Prepare a plan to refactor in logical batches.
Tip: Use a code search tool to quickly locate all instances. - 2
Decide on semantics
Determine if the anchor navigates or triggers an action. If it navigates, keep a real href; if not, consider using a button or real URL with progressive enhancement.
Tip: Aim for semantic anchors with progressive enhancement. - 3
Refactor anchor tags
Replace javascript: hrefs with real URLs or href="#" and move logic into a separate script file.
Tip: Keep markup clean and logic centralized. - 4
Implement centralized handler
Attach event listeners in a single module, using data-action or data attributes to dispatch actions.
Tip: Avoid inline handlers and keep tests focused. - 5
Test accessibility and SEO
Test with JavaScript disabled, verify keyboard navigation and screen reader labels, and ensure link semantics remain intact.
Tip: Use a11y testing tools and manual checks. - 6
Roll out and monitor
Add lint rules or code-review checks to prevent future inline JS usage and monitor for regressions.
Tip: Automate checks in CI to catch new occurrences.
Prerequisites
Keyboard Shortcuts
| Action | Shortcut |
|---|---|
| Open DevToolsIn Chromium-based browsers | Ctrl+⇧+I |
| Open ConsoleDevTools Console tab | Ctrl+⇧+J |
| Copy code snippetText selection in code blocks | Ctrl+C |
| Format code in editorCode editor formatting | Ctrl+⇧+F |
Questions & Answers
What is javascript in href and why is it discouraged?
javascript in href embeds JS code in an anchor tag, triggering code on click. This pattern is discouraged due to accessibility, security, and maintainability concerns. Prefer real URLs and unobtrusive JavaScript attachments.
JavaScript in href is when a link runs code instead of navigating. It hurts accessibility and security, so avoid it and use unobtrusive event handlers.
What are safe alternatives to javascript in href?
Use real URLs for navigation and attach behavior with addEventListener in a separate script. For non-navigational actions, consider buttons or anchors with data attributes and a centralized JS handler.
The safe approach is to keep navigation real and handle actions with separate JavaScript.
Is javascript in href accessible with assistive technologies?
Inline JavaScript in href can be ignored by screen readers or misrepresented by assistive technologies. Refactoring to unobtrusive JS improves compatibility and predictability across devices.
Accessibility is compromised with inline JS in href; refactor to separate JS for better support.
How do I convert existing code to unobtrusive JS?
Search for href="javascript:" patterns, replace with a real URL or href="#", and attach the behavior via a script using addEventListener. Start with the most-used links and test thoroughly.
You refactor by moving logic into JavaScript files and keeping the HTML clean.
Are there cases where javascript in href is acceptable?
In rare cases where the anchor is purely a UI trigger not intended to navigate, it may be used with proper ARIA roles and fallback navigation. However, this is discouraged and should be avoided when possible.
There are few acceptable cases; usually you should avoid it and use progressive enhancement instead.
What to Remember
- Avoid javascript in href; use real URLs where possible
- Attach behavior with addEventListener instead of inline handlers
- Use progressive enhancement to support users with JS disabled
- Keep HTML semantic and separate from JavaScript logic
- Audit and refactor codebases to migrate away from inline JS in href