Statutory payroll and salary-tax maths for India, as tested JavaScript with zero dependencies — plus the underlying slab data as plain JSON you can use in any language.
FY 2026-27 (AY 2027-28). Income tax under the new regime, gratuity under the 2025 Labour Codes, HRA exemption under Section 10(13A), and professional tax for every state that levies it.
Interactive documentation → — every function with a live playground, the edge cases worked through with real numbers, and the slab data in full. The page runs this package in your browser, so the figures there are the figures the library returns.
npm install india-payroll-rules # or just copy src/index.js — it has no dependenciesconst rules = require("india-payroll-rules");
rules.inHandSalary({ ctc: 1200000 });
// { gross: 1128000, employeePf: 72000, incomeTax: 0, monthlyNet: 87800, ... }
rules.gratuity({ lastDrawnWage: 40000, years: 6, months: 4 });
// { amount: 138462, countedYears: 6, eligible: true, exempt: 138462, taxable: 0 }
rules.professionalTax("karnataka", 30000);
// { monthly: 200, annual: 2400, levied: true, state: "Karnataka" }These formulas look trivial and are widely implemented wrong. The cases below are the ones we kept finding broken in calculators, spreadsheets and payroll code — each one has a test here.
Under the new regime, tax is nil when taxable income is within ₹12,00,000. Just past it, most implementations jump straight to the full slab figure. The law instead caps the tax at the amount by which you crossed the limit.
| Taxable income | Naive slab tax | Correct tax (with relief + cess) |
|---|---|---|
| ₹12,00,000 | ₹0 | ₹0 |
| ₹12,41,000 | ₹66,150 | ₹42,640 |
The Payment of Gratuity Act counts a part-year as a full year when service exceeds six months. Exactly six months does not round up — a boundary many calculators get wrong.
rules.gratuity({ lastDrawnWage: 40000, years: 6, months: 6 }).countedYears; // 6
rules.gratuity({ lastDrawnWage: 40000, years: 6, months: 7 }).countedYears; // 7Covered employers (10 or more employees) pay wage × 15/26 × years. Employers outside the Act
pay half a month's salary per completed year — 15/30, with no rounding up.
Section 10(10) is cumulative across every employer you ever receive gratuity from, so exemption already used reduces what remains. Government employees are fully exempt.
rules.gratuity({ lastDrawnWage: 500000, years: 30, exemptionAlreadyUsed: 1500000 }).exempt;
// 500000 — not 2000000Article 276 caps professional tax at ₹2,500 per year regardless of what a state's slabs add up to. Tamil Nadu, Kerala and Madhya Pradesh also levy half-yearly or annually rather than monthly, so their "monthly" figures are averages.
Under the Labour Codes in force from 21 November 2025, fixed-term employees become eligible after one year of service instead of five. The codes also require the wage base to be at least 50% of total pay, which raises gratuity for salary structures built around a small basic.
| Function | Returns |
|---|---|
incomeTax(taxableIncome) |
tax under the new regime incl. 87A relief, surcharge and 4% cess |
slabTax(taxableIncome) |
slab tax alone, before rebate/surcharge/cess |
surchargeRate(taxableIncome) |
0, 0.10, 0.15 or 0.25 |
inHandSalary({ ctc, basicPercent, pf, professionalTax }) |
full CTC → monthly take-home breakdown |
gratuity({ lastDrawnWage, years, months, covered, employeeType, exemptionAlreadyUsed }) |
amount, eligibility, exempt and taxable parts |
hraExemption({ basic, da, hraReceived, rentPaid, metro }) |
exemption plus all three limbs |
professionalTax(state, monthlySalary) |
monthly and annual PT, capped at ₹2,500 |
statesWithProfessionalTax() |
list of state slugs |
pf accepts "full" (12% of basic), "capped" (₹1,800/month) or "none".
employeeType accepts "permanent", "fixedTerm" or "government".
The slab data is plain JSON, usable without the library:
data/income-tax.json— new-regime slabs, standard deduction, rebate, surcharge bands, cessdata/professional-tax.json— monthly PT slabs for 11 states, the 9 states and UTs that levy none, and per-state notes
Stated explicitly because they change the answer: basic is 50% of CTC by default; the employer's PF contribution is treated as part of CTC and the employee contributes the same; professional tax defaults to ₹2,400/year. Gratuity provisions, insurance premiums and variable pay are not modelled — pass the fixed portion of CTC for a realistic monthly figure.
node --test test/rules.test.js # 17 tests, no test framework neededEvery rule here is used in production by the free calculators at klair.in, which run entirely in the browser and store nothing:
- In-hand salary calculator — CTC to monthly take-home
- Gratuity calculator — with the tax-free limit
- HRA exemption calculator — the three-limb test
- Professional tax calculator — state by state
- Full & final settlement calculator
Cross-checked against the relevant sections and, where states publish them, the notified slabs. Tax law changes and states revise professional tax in their budgets — verify anything you rely on in production, and open an issue if you find a discrepancy. This is not tax advice.