Tambahkan fitur perhitungan dana pendidikan profesional ke website Anda hanya dengan satu script.
Script ini dibuat dengan HTML, Tailwind CSS, dan Chart.js, serta dilengkapi:
- Form Input Validasi Otomatis untuk biaya, tahun, inflasi, dan return investasi.
- Perhitungan Finansial Akurat termasuk proyeksi biaya masa depan dan tabungan bulanan.
- Grafik Interaktif menggunakan Chart.js untuk memvisualisasikan pertumbuhan tabungan.
- Tabel Rinci Bulanan yang dapat diekspor langsung ke CSV.
- UI Modern & Responsif siap integrasi ke proyek Anda tanpa banyak modifikasi.
💻 Cocok untuk developer yang ingin menambah value pada situs finansial, portal edukasi, atau aplikasi perencanaan keuangan — tanpa harus membangun kalkulator dari nol.
Script HTML
Lelah dengan iklan? Hanya dengan IDR 833 / hari, buka konten eksklusif dan nikmati pengalaman tanpa iklan. Selengkapnya.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kalkulator Dana Pendidikan</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<style>
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #1e3a8a, #3b82f6);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 1rem;
}
.calculator-container {
background: white;
border-radius: 1.5rem;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
padding: 2.5rem;
width: 100%;
max-width: 800px;
max-height: 90vh;
overflow-y: auto;
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.result-card {
background: #f8fafc;
border-radius: 1rem;
padding: 2rem;
margin-top: 2rem;
transition: all 0.3s ease;
}
.input-group {
position: relative;
display: flex;
align-items: center;
background: #f9fafb;
border-radius: 0.75rem;
border: 2px solid #e5e7eb;
transition: all 0.3s ease;
padding: 0.5rem 1rem;
}
.input-group:focus-within {
border-color: #3b82f6;
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1);
}
.input-field {
background: transparent;
border: none;
outline: none;
width: 100%;
padding: 0.5rem;
font-size: 0.875rem;
color: #1f2937;
}
.input-icon {
color: #6b7280;
margin-right: 0.5rem;
}
.btn-primary {
background: #3b82f6;
transition: background 0.3s ease, transform 0.2s ease;
}
.btn-primary:hover {
background: #1d4ed8;
transform: translateY(-2px);
}
.btn-secondary {
background: #6b7280;
transition: background 0.3s ease, transform 0.2s ease;
}
.btn-secondary:hover {
background: #4b5563;
transform: translateY(-2px);
}
.table-container {
max-height: 400px;
overflow-y: auto;
border-radius: 0.75rem;
margin-top: 1rem;
}
table {
border-collapse: separate;
border-spacing: 0;
width: 100%;
}
th, td {
border-bottom: 1px solid #e5e7eb;
padding: 0.75rem 1rem;
}
th:first-child, td:first-child {
border-left: 1px solid #e5e7eb;
}
th:last-child, td:last-child {
border-right: 1px solid #e5e7eb;
}
th {
background: #f1f5f9;
position: sticky;
top: 0;
z-index: 10;
}
.error-message {
color: #dc2626;
font-size: 0.75rem;
margin-top: 0.25rem;
}
@media (max-width: 640px) {
.calculator-container {
padding: 1.5rem;
}
.table-container {
max-height: 300px;
}
}
</style>
</head>
<body>
<div class="calculator-container">
<h1 class="text-3xl font-extrabold text-gray-800 mb-8 text-center">Kalkulator Dana Pendidikan</h1>
<div class="grid gap-8">
<div>
<label for="currentCost" class="block text-sm font-medium text-gray-700 mb-2">Biaya Pendidikan Saat Ini (IDR)</label>
<div class="input-group">
<span class="input-icon">Rp</span>
<input type="text" id="currentCost" class="input-field" placeholder="Masukkan biaya saat ini" required>
</div>
<p id="currentCostError" class="error-message hidden">Biaya harus lebih dari Rp 0</p>
</div>
<div>
<label for="years" class="block text-sm font-medium text-gray-700 mb-2">Tahun Hingga Dibutuhkan</label>
<div class="input-group">
<span class="input-icon">📅</span>
<input type="number" id="years" class="input-field" placeholder="Masukkan jumlah tahun" required>
</div>
<p id="yearsError" class="error-message hidden">Tahun harus antara 1-30 tahun</p>
</div>
<div>
<label for="inflationRate" class="block text-sm font-medium text-gray-700 mb-2">Tingkat Inflasi (% per Tahun)</label>
<div class="input-group">
<span class="input-icon">%</span>
<input type="number" id="inflationRate" step="0.01" class="input-field" placeholder="Masukkan tingkat inflasi" required>
</div>
<p id="inflationRateError" class="error-message hidden">Inflasi harus antara 0-20%</p>
</div>
<div>
<label for="returnRate" class="block text-sm font-medium text-gray-700 mb-2">Tingkat Pengembalian Investasi (% per Tahun)</label>
<div class="input-group">
<span class="input-icon">📈</span>
<input type="number" id="returnRate" step="0.01" class="input-field" placeholder="Masukkan tingkat pengembalian" required>
</div>
<p id="returnRateError" class="error-message hidden">Pengembalian harus antara 0-20%</p>
</div>
<div class="flex space-x-4">
<button onclick="calculateSavings()" class="w-full btn-primary text-white font-semibold py-3 rounded-lg shadow-md">Hitung</button>
<button onclick="exportToCSV()" class="w-full btn-secondary text-white font-semibold py-3 rounded-lg shadow-md hidden" id="exportButton">Ekspor ke CSV</button>
</div>
</div>
<div id="result" class="result-card hidden">
<h2 class="text-xl font-semibold text-gray-800 mb-6">Hasil Perhitungan</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
<div class="bg-blue-50 p-4 rounded-lg">
<p class="font-medium text-gray-700">Biaya Masa Depan</p>
<p id="futureCost" class="text-lg font-bold text-blue-600"></p>
</div>
<div class="bg-blue-50 p-4 rounded-lg">
<p class="font-medium text-gray-700">Tabungan Bulanan</p>
<p id="monthlySavings" class="text-lg font-bold text-blue-600"></p>
</div>
<div class="bg-blue-50 p-4 rounded-lg">
<p class="font-medium text-gray-700">Total Tabungan</p>
<p id="totalSavings" class="text-lg font-bold text-blue-600"></p>
</div>
<div class="bg-blue-50 p-4 rounded-lg">
<p class="font-medium text-gray-700">Total Bunga</p>
<p id="totalInterest" class="text-lg font-bold text-blue-600"></p>
</div>
</div>
<div class="mb-6">
<h3 class="text-lg font-semibold text-gray-700 mb-4">Grafik Pertumbuhan Tabungan</h3>
<canvas id="savingsChart" height="200"></canvas>
</div>
<div id="savingsTable">
<h3 class="text-lg font-semibold text-gray-700 mb-4">Tabel Tabungan Bulanan</h3>
<div class="table-container">
<table class="w-full text-sm text-left text-gray-600">
<thead>
<tr class="bg-gray-100">
<th class="px-4 py-3 rounded-tl-lg">Bulan</th>
<th class="px-4 py-3">Tabungan Awal</th>
<th class="px-4 py-3">Kontribusi</th>
<th class="px-4 py-3">Bunga</th>
<th class="px-4 py-3">Tabungan Akhir</th>
</tr>
</thead>
<tbody id="savingsBody"></tbody>
</table>
</div>
</div>
</div>
</div>
<script>
let chartInstance = null;
function formatRupiah(number) {
return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 2 }).format(number);
}
function formatRupiahForCSV(number) {
return formatRupiah(number).replace(/\u00A0/g, ' ');
}
function formatInputNumber(value) {
value = value.replace(/[^\d]/g, '');
return value.replace(/\B(?=(\d{3})+(?!\d))/g, '.');
}
function parseRupiah(value) {
return parseFloat(value.replace(/[^\d]/g, '')) || 0;
}
function validateInputs(currentCost, years, inflationRate, returnRate) {
let isValid = true;
document.getElementById('currentCostError').classList.add('hidden');
document.getElementById('yearsError').classList.add('hidden');
document.getElementById('inflationRateError').classList.add('hidden');
document.getElementById('returnRateError').classList.add('hidden');
if (currentCost <= 0) {
document.getElementById('currentCostError').classList.remove('hidden');
isValid = false;
}
if (years < 1 || years > 30 || isNaN(years)) {
document.getElementById('yearsError').classList.remove('hidden');
isValid = false;
}
if (inflationRate < 0 || inflationRate > 20 || isNaN(inflationRate)) {
document.getElementById('inflationRateError').classList.remove('hidden');
isValid = false;
}
if (returnRate < 0 || returnRate > 20 || isNaN(returnRate)) {
document.getElementById('returnRateError').classList.remove('hidden');
isValid = false;
}
return isValid;
}
document.getElementById('currentCost').addEventListener('input', function(e) {
const cursorPosition = e.target.selectionStart;
const value = e.target.value.replace(/[^\d]/g, '');
e.target.value = formatInputNumber(value);
const newValue = e.target.value;
const newCursorPosition = cursorPosition + (newValue.length - value.length);
e.target.setSelectionRange(newCursorPosition, newCursorPosition);
});
function calculateSavings() {
const currentCost = parseRupiah(document.getElementById('currentCost').value);
const years = parseInt(document.getElementById('years').value);
const inflationRate = parseFloat(document.getElementById('inflationRate').value) / 100;
const returnRate = parseFloat(document.getElementById('returnRate').value) / 100 / 12; // Bulanan
const resultDiv = document.getElementById('result');
const exportButton = document.getElementById('exportButton');
const savingsBody = document.getElementById('savingsBody');
if (!validateInputs(currentCost, years, inflationRate, returnRate * 12 * 100)) {
return;
}
const futureCost = currentCost * Math.pow(1 + inflationRate, years);
const monthlySavings = futureCost * returnRate / (Math.pow(1 + returnRate, years * 12) - 1);
const totalSavings = monthlySavings * years * 12;
let schedule = [];
let balance = 0;
let totalInterest = 0;
for (let i = 1; i <= years * 12; i++) {
const startBalance = balance;
const contribution = monthlySavings;
const interest = balance * returnRate;
balance = startBalance + contribution + interest;
totalInterest += interest;
schedule.push({
month: i,
startBalance,
contribution,
interest,
endBalance: balance
});
}
document.getElementById('futureCost').textContent = formatRupiah(futureCost);
document.getElementById('monthlySavings').textContent = formatRupiah(monthlySavings);
document.getElementById('totalSavings').textContent = formatRupiah(totalSavings);
document.getElementById('totalInterest').textContent = formatRupiah(totalInterest);
resultDiv.classList.remove('hidden');
exportButton.classList.remove('hidden');
savingsBody.innerHTML = '';
schedule.forEach(row => {
const tr = document.createElement('tr');
tr.classList.add('hover:bg-gray-50');
tr.innerHTML = `
<td class="px-4 py-3">${row.month}</td>
<td class="px-4 py-3">${formatRupiah(row.startBalance)}</td>
<td class="px-4 py-3">${formatRupiah(row.contribution)}</td>
<td class="px-4 py-3">${formatRupiah(row.interest)}</td>
<td class="px-4 py-3">${formatRupiah(row.endBalance)}</td>
`;
savingsBody.appendChild(tr);
});
if (chartInstance) {
chartInstance.destroy();
}
const ctx = document.getElementById('savingsChart').getContext('2d');
chartInstance = new Chart(ctx, {
type: 'line',
data: {
labels: schedule.map(row => `Bulan ${row.month}`),
datasets: [{
label: 'Tabungan Akhir',
data: schedule.map(row => row.endBalance),
borderColor: '#3b82f6',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
fill: true,
tension: 0.4
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return formatRupiah(value);
}
}
}
},
plugins: {
tooltip: {
callbacks: {
label: function(context) {
return formatRupiah(context.parsed.y);
}
}
}
}
}
});
window.savingsData = {
currentCost,
years,
inflationRate: inflationRate * 100,
returnRate: returnRate * 12 * 100,
futureCost,
monthlySavings,
totalSavings,
totalInterest,
schedule
};
}
function exportToCSV() {
if (!window.savingsData) {
alert('Silakan hitung terlebih dahulu.');
return;
}
const { currentCost, years, inflationRate, returnRate, futureCost, monthlySavings, totalSavings, totalInterest, schedule } = window.savingsData;
let csvContent = 'data:text/csv;charset=utf-8,';
csvContent += 'Informasi Tabungan\n';
csvContent += `Biaya Pendidikan Saat Ini,"${formatRupiahForCSV(currentCost)}"\n`;
csvContent += `Tahun Hingga Dibutuhkan,${years}\n`;
csvContent += `Tingkat Inflasi (% per Tahun),${inflationRate.toFixed(2)}\n`;
csvContent += `Tingkat Pengembalian Investasi (% per Tahun),${returnRate.toFixed(2)}\n`;
csvContent += '\nRingkasan\n';
csvContent += `Biaya Masa Depan,"${formatRupiahForCSV(futureCost)}"\n`;
csvContent += `Tabungan Bulanan,"${formatRupiahForCSV(monthlySavings)}"\n`;
csvContent += `Total Tabungan,"${formatRupiahForCSV(totalSavings)}"\n`;
csvContent += `Total Bunga,"${formatRupiahForCSV(totalInterest)}"\n`;
csvContent += '\nTabel Tabungan Bulanan\n';
const headers = [
'Bulan',
'Tabungan Awal (IDR)',
'Kontribusi (IDR)',
'Bunga (IDR)',
'Tabungan Akhir (IDR)'
];
const rows = schedule.map(row => [
row.month,
`"${formatRupiahForCSV(row.startBalance)}"`,
`"${formatRupiahForCSV(row.contribution)}"`,
`"${formatRupiahForCSV(row.interest)}"`,
`"${formatRupiahForCSV(row.endBalance)}"`
]);
csvContent += headers.join(',') + '\n';
rows.forEach(row => {
csvContent += row.join(',') + '\n';
});
const encodedUri = encodeURI(csvContent);
const link = document.createElement('a');
link.setAttribute('href', encodedUri);
link.setAttribute('download', 'kalkulator_dana_pendidikan.csv');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
</body>
</html>
Lelah dengan iklan? Hanya dengan IDR 833 / hari, buka konten eksklusif dan nikmati pengalaman tanpa iklan. Selengkapnya.

