How do you pass value to the JS controller while using hyperlinks?

Why this matters

When building Salesforce UIs—Visualforce, Aura components, or Lightning Web Components—you often need to make hyperlinks interactive and pass contextual data (record Ids, flags, or indexes) to a JavaScript controller. Choosing the right approach improves maintainability, security, and accessibility.

Common approaches (with examples)

1) Visualforce: use apex:outputLink / <a> with onclick

In Visualforce you can use a standard <a> and call a JavaScript function on click. Pass values using the query string or embed them as data attributes.

<apex:page controller="MyController">
<script>
function handleClick(id){
// call remote action or handle client-side logic
MyController.remoteMethod(id, function(result){
console.log(result);
});
}
</script>

<a href="javascript:void(0);" onclick="handleClick('{!Account.Id}')">Open Account</a>
</apex:page>

Better (safer) approach: use data-* attributes and read them in JS:

<a href="javascript:void(0);" data-id="{!Account.Id}" onclick="handleClickFromEvent(event)">Open Account</a>

<script>
function handleClickFromEvent(e){
var id = e.currentTarget.getAttribute('data-id');
// or e.currentTarget.dataset.id
console.log(id);
}
</script>

2) Aura components: use data-attributes or component attributes

Aura lets you wire controller handlers to DOM events but treat them as standard JavaScript events. Prefer data-* attributes or pass component attributes by using event.getSource() for components that expose values.

<a href="javascript:void(0);" data-id="{!v.recordId}" onclick="{!c.handleClick}">Open Record</a>

// Controller (client-side JS)
({
handleClick : function(component, event, helper) {
// event is a DOM event; use currentTarget to get data attribute
var recordId = event.currentTarget.dataset.id;
console.log(recordId);
// now call helper or server action
}
})

If you use an Aura component (like lightning:button), use event.getSource().get('v.name') or a custom attribute exposed through the component.

3) Lightning Web Components (LWC): use data attributes or pass via closure

In LWC, event handlers receive a DOM event; read dataset from the currentTarget. Example:

// template.html
<template>
<a href="#" data-id={recordId} onclick={handleClick}>Open</a>
</template>

// component.js
import { LightningElement, api } from 'lwc';
export default class MyLink extends LightningElement {
@api recordId;
handleClick(event) {
event.preventDefault();
const id = event.currentTarget.dataset.id;
console.log('Clicked id', id);
// call Apex via @wire or imperative apex call
}
}

Note: avoid inline inline JS expressions in templates; use data attributes or closure-binding for readability.

4) Encode value in the URL (query string)

If the link navigates to another page, pass parameters in the query string and read them server-side or in the target page JavaScript.

<a href="/apex/TargetPage?id={!Account.Id}">Open Target</a>

Best practices

  • Prefer data-* attributes over building JavaScript strings — cleaner and less error-prone.
  • Use event.currentTarget.dataset (not event.target) to ensure you get the element with the attribute, even if a child element was clicked.
  • Escape values when embedding server-side variables to prevent XSS issues.
  • For navigation, prefer URL parameters or Salesforce navigation services (Lightning Navigation) instead of raw href hacks.
  • Keep markup semantic and accessible: use role and keyboard handlers if the link performs actions rather than navigation.

Quick reference

Read dataset example:

const id = event.currentTarget.dataset.id; // works in VF, Aura, LWC

Call Apex after retrieving value:

MyController.someRemoteAction(id, callback); // Visualforce RemoteAction
// or
component.get("c.serverSideMethod").setParams({recordId: id}); // Aura
// or
import apexMethod from '@salesforce/apex/MyClass.method'; apexMethod({id}); // LWC

Conclusion

Passing values to JS controllers through hyperlinks is straightforward when you use data attributes and read them from the event (preferably event.currentTarget.dataset). Choose the pattern that fits the framework (Visualforce, Aura, LWC), keep code secure, and prefer declarative navigation where possible.