Service Cost Calculator Development on Website
A cost calculator is one of the most converting elements on a services website. A person wants to understand the price before talking to a manager. If the calculator provides a realistic estimate, it lowers the entry barrier and filters non-target inquiries.
Pricing Models in Calculators
Additive — total price = sum of components. Suitable for service builders: "basic plan + option A + option B".
Multiplicative — base price is multiplied by coefficients. Typical for volume-based services: price per unit × quantity × adjustment coefficient.
Formula-based — arbitrary formula from parameters. Requires an expression parser or explicit JS code.
Matrix — price is taken from a table by the intersection of parameters (for example, city × delivery type).
Architecture: Configuration Separate from Code
const pricingConfig = {
base: 5000,
options: {
hosting: { label: 'Hosting for one year', price: 1200 },
ssl: { label: 'SSL certificate', price: 0, note: 'free' },
backup: { label: 'Daily backups', price: 800 },
support: { label: 'Technical support 1 year', price: 3600 },
},
multipliers: {
pages: { label: 'Number of pages', perUnit: 500, freeUnits: 5 },
languages: { label: 'Language versions', perUnit: 2000, freeUnits: 1 },
},
discounts: [
{ minTotal: 20000, percent: 5 },
{ minTotal: 50000, percent: 10 },
],
};
function calculateTotal(selected, counts) {
let total = pricingConfig.base;
// Options
for (const key of selected) {
total += pricingConfig.options[key]?.price ?? 0;
}
// Multipliers
for (const [key, count] of Object.entries(counts)) {
const m = pricingConfig.multipliers[key];
if (!m) continue;
const billable = Math.max(0, count - m.freeUnits);
total += billable * m.perUnit;
}
// Discounts
const discount = [...pricingConfig.discounts]
.reverse()
.find(d => total >= d.minTotal);
if (discount) {
total = total * (1 - discount.percent / 100);
}
return Math.round(total);
}
React Implementation
function ServiceCalculator({ config }) {
const [selectedOptions, setSelectedOptions] = useState(new Set());
const [counts, setCounts] = useState({ pages: 5, languages: 1 });
const total = calculateTotal([...selectedOptions], counts);
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency', currency: 'USD', maximumFractionDigits: 0,
}).format(total);
const toggleOption = (key) => {
setSelectedOptions(prev => {
const next = new Set(prev);
next.has(key) ? next.delete(key) : next.add(key);
return next;
});
};
return (
<div className="calculator">
<section className="calculator__options">
{Object.entries(config.options).map(([key, opt]) => (
<label key={key} className="calculator__option">
<input
type="checkbox"
checked={selectedOptions.has(key)}
onChange={() => toggleOption(key)}
/>
<span>{opt.label}</span>
<span className="price">
{opt.price > 0 ? `+${opt.price.toLocaleString('en')}` : opt.note}
</span>
</label>
))}
</section>
<section className="calculator__counters">
{Object.entries(config.multipliers).map(([key, m]) => (
<div key={key} className="calculator__counter">
<label>{m.label}</label>
<input
type="range"
min={m.freeUnits}
max={50}
value={counts[key] ?? m.freeUnits}
onChange={e => setCounts(p => ({ ...p, [key]: +e.target.value }))}
/>
<output>{counts[key] ?? m.freeUnits}</output>
</div>
))}
</section>
<div className="calculator__total">
<span>Total</span>
<strong>{formatted}</strong>
</div>
<button className="calculator__cta" onClick={() => openRequestForm(total)}>
Submit Request
</button>
</div>
);
}
Passing Amount to Request Form
When a user clicks "Submit Request" — the form should receive selected parameters and the calculated amount:
function openRequestForm(total, selectedOptions, counts) {
// Option 1: parameters in URL
const params = new URLSearchParams({
estimated_cost: total,
options: [...selectedOptions].join(','),
});
window.location.href = `/contact?${params}`;
// Option 2: hidden form fields on the same page
document.getElementById('field-estimated-cost').value = total;
document.getElementById('field-options').value = [...selectedOptions].join(', ');
document.getElementById('contact-modal').showModal();
}
Storing Price Configuration on Server
If prices change frequently — don't hardcode them in JS. An endpoint /api/pricing returns the current configuration:
// Laravel
public function getPricingConfig()
{
return response()->json(
Cache::remember('pricing_config', 3600, fn() =>
PricingConfig::where('active', true)->first()?->config ?? []
)
);
}
On the frontend, load it once on component mount and cache in sessionStorage.
Timeframe
A static calculator with options and sliders, passing data to a form — 2–3 working days. With dynamic configuration from CMS, discount rules, multiple currencies, and analytics of selected parameters — 5–7 days.







