Question
JavaScript Links: Should You Use href="#" or javascript:void(0)?
Question
I want to create a link whose only purpose is to run JavaScript code. Which of these approaches is better in terms of behavior, performance, and HTML validity?
<script>
function myJsFunc() {
alert("myJsFunc");
}
</script>
<a href="#" onclick="myJsFunc();">Run JavaScript Code</a>
Or this version:
<script>
function myJsFunc() {
alert("myJsFunc");
}
</script>
<a href="javascript:void(0)" onclick="myJsFunc();">Run JavaScript Code</a>
If a link exists only to trigger JavaScript, which option should be used, and is there a better semantic alternative?
Short Answer
By the end of this page, you will understand why href="#" and href="javascript:void(0)" are usually not the best choices for triggering JavaScript actions. You will learn the semantic difference between links and buttons, how browsers handle each option, and the recommended modern approach: use a <button> for actions and an <a> only for real navigation.
Concept
In HTML, links and buttons have different jobs:
- An
<a>element is for navigation. - A
<button>element is for actions such as opening a menu, submitting data, toggling UI, or running JavaScript.
That distinction matters because browsers, assistive technologies, search engines, and other developers all expect these elements to behave according to their meaning.
Why href="#" is problematic
When you use:
<a href="#" onclick="myJsFunc();">Run JavaScript Code</a>
# is a URL fragment. Clicking it usually means “navigate to the top of the page” or “navigate to the element with the matching fragment id.” Even if your onclick handler runs, the browser may still perform navigation unless you prevent the default behavior.
Common side effects:
- The page may jump to the top.
- The URL may change to include
#. - Browser history may be affected.
- The element is pretending to be a link even though it is not really navigating.
Why javascript:void(0) is also not ideal
When you use:
<a href="javascript:void(0)" onclick="myJsFunc();">Run JavaScript Code</a>
The javascript: URL scheme tells the browser to execute JavaScript from the href itself. void(0) makes the expression return undefined, so the browser does not try to replace the page with a result.
Although this avoids the jump-to-top behavior of #, it still has issues:
- It mixes behavior into HTML markup.
- It is harder to maintain.
- It is considered poor practice in modern development.
- Some security tools and content policies discourage inline JavaScript.
- It still uses a link for something that is not navigation.
What should you use instead?
If the element performs an action, use a button:
<button type="button" id="runAction">Run JavaScript Code</button>
<script>
document.getElementById("runAction").addEventListener("click", myJsFunc);
function myJsFunc() {
alert("myJsFunc");
}
</script>
This is better because:
- It is semantic: buttons are for actions.
- It is more accessible by default.
- It separates HTML structure from JavaScript behavior.
- It avoids fake navigation.
- It is easier to test and maintain.
Why this matters in real programming
In real projects, clean semantics lead to better:
- accessibility n- maintainability
- keyboard support
- browser behavior
- team readability
A developer reading your code should immediately know whether clicking something should navigate somewhere or perform an action. Using the right element makes that obvious.
Mental Model
Think of HTML elements like tools in a toolbox:
- A link is like a road sign: it sends you to another place.
- A button is like a doorbell: pressing it causes an action.
If you install a doorbell that secretly acts like a road sign, people will be confused. Browsers and screen readers feel the same way.
So the rule of thumb is simple:
- Going somewhere? Use a link.
- Doing something? Use a button.
Syntax and Examples
1. Using a link for real navigation
<a href="/profile">Go to Profile</a>
Use this when the user should move to another page or location.
2. Using a button for JavaScript actions
<button type="button" id="showMessage">Run JavaScript Code</button>
<script>
function myJsFunc() {
alert("myJsFunc");
}
document.getElementById("showMessage").addEventListener("click", myJsFunc);
</script>
This is the recommended modern approach.
3. If you must use a link, use a real URL
<a href="/download" id="downloadLink">Download</a>
Then JavaScript can enhance behavior if needed:
<script>
document.getElementById("downloadLink").addEventListener("click", function (event) {
console.log("Tracking download before navigation");
});
</script>
The link still works as a normal link.
4. Avoid these patterns for actions
<a href="#" onclick="myJsFunc();">Run</a>
<a href="javascript:void(0)" onclick="myJsFunc();">Run</a>
These work in many cases, but they are not the best semantic or maintainable choice.
5. If href="#" is already in old code
You often need to stop default navigation:
<a href="#" id="oldLink">Run</a>
<script>
document.getElementById("oldLink").addEventListener("click", function (event) {
event.preventDefault();
myJsFunc();
});
function myJsFunc() {
alert("myJsFunc");
}
</script>
This is safer than relying on inline onclick, but a button is still better if there is no navigation.
Step by Step Execution
Consider this recommended example:
<button type="button" id="runAction">Run JavaScript Code</button>
<script>
function myJsFunc() {
alert("myJsFunc");
}
document.getElementById("runAction").addEventListener("click", myJsFunc);
</script>
What happens step by step
- The browser reads the HTML and creates a button on the page.
- The JavaScript defines the
myJsFuncfunction. document.getElementById("runAction")finds the button.addEventListener("click", myJsFunc)tells the browser:- when this button is clicked,
- call
myJsFunc.
- The user clicks the button.
- The browser fires a
clickevent. myJsFunc()runs.alert("myJsFunc")displays the message.
Compare that with href="#"
<a href="#" onclick="myJsFunc();">Run</a>
When clicked:
- The browser sees a link.
- The
onclickcode runs. - The browser may then follow
href="#". - The page may jump to the top or update the URL fragment.
That extra navigation behavior is usually unwanted when the element is only meant to trigger code.
Real World Use Cases
Use a <button> for actions like:
- Opening a modal dialog
- Toggling a dropdown menu
- Showing or hiding password text
- Starting a file upload
- Applying a filter in a dashboard
- Adding an item to a cart with JavaScript
- Expanding an accordion section
Example:
<button type="button" id="toggleMenu">Toggle Menu</button>
Use an <a> for navigation like:
- Going to a product page
- Moving to another route in a single-page app
- Jumping to a section of the same page
- Downloading a file from a URL
- Opening documentation
Example:
<a href="/products/42">View Product</a>
In APIs and web apps
Developers often attach JavaScript actions to buttons for:
- submitting AJAX requests
- refreshing data tables
- retrying failed operations
- opening side panels
- triggering export actions
Using a button makes intent clear and avoids fake URLs.
Real Codebase Usage
In real codebases, developers usually avoid inline handlers like onclick="..." and instead attach behavior in JavaScript.
Common pattern: separate structure and behavior
<button type="button" id="saveBtn">Save</button>
document.getElementById("saveBtn").addEventListener("click", function () {
console.log("Saving...");
});
This keeps HTML cleaner and JavaScript easier to organize.
Guard clauses in event handlers
document.getElementById("saveBtn").addEventListener("click", function () {
if (!formIsValid()) {
return;
}
saveData();
});
Developers often return early when validation fails.
Progressive enhancement
If navigation is real, developers keep a valid href so the page still works without JavaScript:
<a href="/reports/export" id="exportLink">Export</a>
document.getElementById("exportLink").addEventListener("click", function () {
console.log("Track export click");
});
Error handling with action buttons
document.getElementById("retryBtn").addEventListener("click", async function () {
try {
await fetchData();
} catch (error) {
console.error("Retry failed", error);
}
});
Why teams prefer this approach
- better accessibility
- easier testing
- clearer intent
- less inline JavaScript
- fewer accidental navigation bugs
Common Mistakes
1. Using a link when a button is needed
Broken example:
<a href="#" id="openModal">Open Modal</a>
Problem:
- This is not navigation.
- It may jump to the top of the page.
Better:
<button type="button" id="openModal">Open Modal</button>
2. Forgetting to prevent default on href="#"
Broken example:
<a href="#" id="runLink">Run</a>
<script>
document.getElementById("runLink").addEventListener("click", function () {
myJsFunc();
});
</script>
Problem:
- The function runs, but the browser still follows
#.
Fix:
<a href="#" id="runLink">Run</a>
<script>
document.getElementById("runLink").addEventListener("click", function (event) {
event.preventDefault();
myJsFunc();
});
</script>
3. Using javascript: URLs
Broken style:
<a href="javascript:void(0)">Run</a>
Problem:
- Behavior is embedded in markup.
- It is outdated and harder to maintain.
Better:
<button type="button">Run</button>
4. Relying on inline onclick
Less maintainable:
<button type="button" onclick="myJsFunc()">Run</button>
Better:
<button type="button" id="runBtn">Run</button>
<script>
document.getElementById("runBtn").addEventListener("click", myJsFunc);
</script>
5. Forgetting button type inside forms
Broken example:
<form>
<button id="runBtn">Run</button>
</form>
Problem:
- A button inside a form defaults to
type="submit"in many cases.
Fix:
<form>
<button type="button" id="runBtn">Run</button>
</form>
6. Assuming performance differences matter here
Between # and javascript:void(0), performance differences are not the real issue. The important concerns are:
- semantics
- accessibility
- maintainability
- unwanted browser behavior
Comparisons
| Approach | Main purpose | Good choice for JavaScript-only action? | Notes |
|---|---|---|---|
<a href="#"> | Fragment navigation | No | May jump to top or change URL unless prevented |
<a href="javascript:void(0)"> | Execute JS from URL | No | Outdated style, mixes behavior into markup |
<button type="button"> | Trigger action | Yes | Best semantic choice for actions |
<a href="/real-url"> | Real navigation | Yes, if navigating | Best when the element should go somewhere |
href="#" vs javascript:void(0)
| Feature | # | javascript:void(0) |
|---|---|---|
| Changes URL fragment | Usually yes | No |
| Can jump page position | Yes | No |
| Semantic for action-only UI | Poor | Poor |
| Modern best practice | No | No |
| Requires workaround | Often preventDefault() | Still not recommended |
Button vs Link
| Element | Use when | Keyboard/accessibility meaning |
|---|---|---|
<button> | The user triggers an action | Announced and behaved as a control |
<a> | The user navigates to another location | Announced and behaved as a link |
Cheat Sheet
Quick rule
- Use
<a>for navigation - Use
<button>for actions
Avoid for JS-only actions
<a href="#">...</a>
<a href="javascript:void(0)">...</a>
Recommended pattern
<button type="button" id="runBtn">Run</button>
<script>
document.getElementById("runBtn").addEventListener("click", function () {
alert("Hello");
});
</script>
If you are stuck with href="#"
event.preventDefault();
Why avoid inline handlers
Avoid:
<button onclick="doSomething()">Run</button>
Prefer:
element.addEventListener("click", doSomething);
Important edge case
Inside a form, specify button type:
<button type="button">Open Panel</button>
Otherwise it may submit the form.
Best practice summary
- Real destination -> use
<a href="/somewhere"> - UI action -> use
<button type="button"> - Do not use
javascript:URLs in modern code - Do not use
#as a fake link unless maintaining legacy code
FAQ
Is href="#" bad practice?
It is usually a poor choice when the element does not actually navigate anywhere. It can cause page jumping and confusing semantics.
Is javascript:void(0) better than #?
It avoids the jump-to-top behavior, but it is still not the recommended modern approach. A button is usually better.
What should I use instead of href="javascript:void(0)"?
Use a <button type="button"> and attach a click handler with JavaScript.
Can I still use an anchor tag with JavaScript?
Yes, if it has a real destination. JavaScript can enhance the link, but the link should still represent navigation.
Why does clicking href="#" scroll to the top?
Because # refers to the top of the current document when no specific fragment target is given.
Does javascript:void(0) affect page load speed?
In practice, performance is not the important issue here. Semantics, maintainability, and accessibility matter much more.
Are inline onclick handlers allowed?
They work, but they are generally less maintainable than adding event listeners in JavaScript.
What is the most accessible choice for a JavaScript action?
A native <button> is usually the best choice for actions because browsers and assistive technologies already understand how it should behave.
Mini Project
Description
Build a small interface with two controls: one real navigation link and one JavaScript action button. This project demonstrates the core rule behind the original question: links should navigate, while buttons should trigger actions. It also shows how to attach events without inline onclick code.
Goal
Create a page where one element navigates to a section on the page and another element runs JavaScript to show a message counter.
Requirements
- Add a real anchor link that navigates to a section on the same page.
- Add a button that runs JavaScript when clicked.
- Keep JavaScript out of the HTML attributes.
- Show how many times the button has been clicked.
- Make sure the action control does not change the URL or scroll the page.
Keep learning
Related questions
Allow Only Numeric Input (0-9) in HTML Input Using jQuery
Learn how to allow only digits 0-9 in an HTML input using jQuery, with examples, validation tips, common mistakes, and best practices.
Apply CSS !important with jQuery .css()
Learn why jQuery .css() cannot set !important and how to use CSSStyleDeclaration.setProperty() to apply inline important styles safely.
CSS ::before and ::after on Input Elements
Learn why CSS ::before and ::after usually do not work on input elements, what replaced elements are, and practical alternatives.