DEV Community

Profiterole
Profiterole

Posted on

Build a Malaysian Income Tax Calculator in Pure JavaScript

Building a Malaysian Income Tax Calculator in Pure JavaScript

Calculating your Malaysian personal income tax doesn't have to be a mystery. In this tutorial, we'll build a working tax calculator using pure JavaScript and the 2024 LHDN (Inland Revenue Board) tax brackets.

By the end, you'll have a reusable function you can drop into any web project.

The 2024 Malaysian Income Tax Brackets

Malaysia uses a progressive tax system — you only pay the higher rate on income above each threshold. Here are the current rates for residents (chargeable income after deductions):

Chargeable Income (RM) Tax Rate
0 – 5,000 0%
5,001 – 20,000 1%
20,001 – 35,000 3%
35,001 – 50,000 6%
50,001 – 70,000 11%
70,001 – 100,000 19%
100,001 – 400,000 25%
400,001 – 600,000 26%
600,001 – 2,000,000 28%
Above 2,000,000 30%

Note: These rates apply to chargeable income — your gross income minus all eligible reliefs and deductions. For a full breakdown of what you can deduct, see this Malaysia tax filing guide.

Building the Calculator

Step 1: Define the Tax Brackets

const TAX_BRACKETS_2024 = [
  { min: 0,         max: 5000,      rate: 0.00, base: 0 },
  { min: 5001,      max: 20000,     rate: 0.01, base: 0 },
  { min: 20001,     max: 35000,     rate: 0.03, base: 150 },
  { min: 35001,     max: 50000,     rate: 0.06, base: 600 },
  { min: 50001,     max: 70000,     rate: 0.11, base: 1500 },
  { min: 70001,     max: 100000,    rate: 0.19, base: 3700 },
  { min: 100001,    max: 400000,    rate: 0.25, base: 9400 },
  { min: 400001,    max: 600000,    rate: 0.26, base: 84400 },
  { min: 600001,    max: 2000000,   rate: 0.28, base: 136400 },
  { min: 2000001,   max: Infinity,  rate: 0.30, base: 528400 },
];
Enter fullscreen mode Exit fullscreen mode

Each bracket stores:

  • min / max — the income range
  • rate — the marginal rate for income in this band
  • base — tax already accumulated from all lower brackets (speeds up calculation)

Step 2: The Core Calculation Function

function calculateMalaysianTax(chargeableIncome) {
  if (chargeableIncome <= 0) return 0;

  const bracket = TAX_BRACKETS_2024.find(
    (b) => chargeableIncome >= b.min && chargeableIncome <= b.max
  );

  if (!bracket) return 0;

  const incomeInBracket = chargeableIncome - bracket.min + 1;
  const taxInBracket = incomeInBracket * bracket.rate;

  return bracket.base + taxInBracket;
}
Enter fullscreen mode Exit fullscreen mode

How it works:

  1. Find which bracket the chargeable income falls into.
  2. Calculate tax only on the portion within that bracket.
  3. Add the pre-computed base tax from all lower brackets.

Step 3: Add Effective Rate Helper

function getTaxSummary(chargeableIncome) {
  const tax = calculateMalaysianTax(chargeableIncome);
  const effectiveRate = chargeableIncome > 0
    ? ((tax / chargeableIncome) * 100).toFixed(2)
    : 0;

  return {
    chargeableIncome,
    tax: Math.round(tax * 100) / 100,
    effectiveRate: parseFloat(effectiveRate),
  };
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Test It

const examples = [30000, 60000, 120000, 500000];

examples.forEach((income) => {
  const { tax, effectiveRate } = getTaxSummary(income);
  console.log(`RM ${income.toLocaleString()} -> Tax: RM ${tax.toLocaleString()} (${effectiveRate}%)`);
});
Enter fullscreen mode Exit fullscreen mode

Output:

RM 30,000 -> Tax: RM 300 (1.00%)
RM 60,000 -> Tax: RM 2,600 (4.33%)
RM 120,000 -> Tax: RM 14,400 (12.00%)
RM 500,000 -> Tax: RM 110,400 (22.08%)
Enter fullscreen mode Exit fullscreen mode

Building a Simple HTML UI

Drop this into an HTML file for an instant tax calculator:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Malaysia Income Tax Calculator 2024</title>
  <style>
    body { font-family: sans-serif; max-width: 500px; margin: 40px auto; padding: 0 20px; }
    input, button { width: 100%; padding: 10px; margin: 8px 0; font-size: 1rem; box-sizing: border-box; }
    button { background: #1a73e8; color: white; border: none; cursor: pointer; border-radius: 4px; }
    #result { background: #f0f4ff; padding: 16px; border-radius: 8px; margin-top: 16px; display: none; }
  </style>
</head>
<body>
  <h1>Malaysia Income Tax 2024</h1>
  <p>Enter your <strong>chargeable income</strong> (after all reliefs):</p>

  <input type="number" id="income" placeholder="e.g. 60000" min="0" />
  <button onclick="calculate()">Calculate Tax</button>

  <div id="result">
    <p><strong>Chargeable Income:</strong> RM <span id="out-income"></span></p>
    <p><strong>Estimated Tax:</strong> RM <span id="out-tax"></span></p>
    <p><strong>Effective Rate:</strong> <span id="out-rate"></span>%</p>
  </div>

  <script>
    const TAX_BRACKETS_2024 = [
      { min: 0,       max: 5000,      rate: 0.00, base: 0 },
      { min: 5001,    max: 20000,     rate: 0.01, base: 0 },
      { min: 20001,   max: 35000,     rate: 0.03, base: 150 },
      { min: 35001,   max: 50000,     rate: 0.06, base: 600 },
      { min: 50001,   max: 70000,     rate: 0.11, base: 1500 },
      { min: 70001,   max: 100000,    rate: 0.19, base: 3700 },
      { min: 100001,  max: 400000,    rate: 0.25, base: 9400 },
      { min: 400001,  max: 600000,    rate: 0.26, base: 84400 },
      { min: 600001,  max: 2000000,   rate: 0.28, base: 136400 },
      { min: 2000001, max: Infinity,  rate: 0.30, base: 528400 },
    ];

    function calculateMalaysianTax(income) {
      if (income <= 0) return 0;
      const b = TAX_BRACKETS_2024.find(b => income >= b.min && income <= b.max);
      if (!b) return 0;
      return b.base + (income - b.min + 1) * b.rate;
    }

    function calculate() {
      const income = parseFloat(document.getElementById('income').value) || 0;
      const tax = Math.round(calculateMalaysianTax(income) * 100) / 100;
      const rate = income > 0 ? ((tax / income) * 100).toFixed(2) : 0;
      document.getElementById('out-income').textContent = income.toLocaleString();
      document.getElementById('out-tax').textContent = tax.toLocaleString();
      document.getElementById('out-rate').textContent = rate;
      document.getElementById('result').style.display = 'block';
    }
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Important Caveats

This calculator estimates tax on chargeable income — not gross salary. Before using it, subtract your eligible reliefs (self, spouse, children, EPF contributions, lifestyle relief, etc.).

For a complete walkthrough of what you can deduct and how to submit your e-filing to LHDN, check out:
How to File Your Malaysia Tax Return (Step-by-Step)

To understand how to optimise your tax position and the difference between marginal and effective rates:
Malaysia Income Tax Guide for Individuals

Summary

In under 30 lines of JavaScript, you now have:

  • Accurate 2024 LHDN tax brackets
  • Progressive tax calculation with correct band logic
  • Effective rate display
  • A self-contained HTML widget

The calculateMalaysianTax() function is pure — no dependencies, no DOM — so it works equally well in Node.js, React, or a plain browser script.


Found this useful? Consider buying me a coffee — it keeps tutorials like this going!

Top comments (0)