Custom Online Calculator Development: Configs, Animation, Integration

Off-the-shelf calculator plugins often lag, produce incorrect results, and lack the flexibility you need. We build custom online calculators that fit seamlessly into your design and business logic. Our team delivers turnkey solutions—from formula configuration to animation and integration—ensuring reliable performance and ongoing support.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1344
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1307
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1050
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1099
  • Website development for SBH Partners
    Website development for SBH Partners
    1171
  • Website development for Red Pear
    Website development for Red Pear
    596

Picture this: a user enters a loan amount, and the calculator hangs for a second or returns an incorrect result due to a hidden rounding error. This situation is familiar to many — these are typical problems with off-the-shelf plugins: slow rendering, lack of animation, and opaque formulas. Over 10+ years, we have developed a custom calculator architecture that eliminates these shortcomings. Our team has completed over 50 successful projects in this field. Formulas are moved to a config, the UI is built on React with Core Web Vitals in mind, and validation and animation are implemented on a modern stack. This approach allows clients to save up to 30% of their budget on plugin licensing and reduce support costs. In one project, the savings amounted to $1.1k–1.6k per year by eliminating three paid modules. Another client saved $1.8k–2.6k annually on support costs. Below, we break down a real case: a mortgage calculator using the amortization formula.

Why a custom calculator is better than a ready-made solution?

Ready-made plugins often suffer from slow rendering, lack of animation, and hidden errors in formulas. Moreover, they rarely consider accessibility and Core Web Vitals requirements. Custom development gives you full control: you choose the formulas, design, and behavior. For example, in one project, the client used a jQuery plugin that triggered recalculation on every input — causing lag. We rewrote the solution in React with useMemo optimization, and LCP dropped from 4.2 to 1.8 seconds, improving conversion by 18%.

How to move formulas to a config?

The wrong approach is to hardcode formulas directly into event handlers. The right way is to separate calculation logic from the UI. Below is a typical calculator configuration in TypeScript.

// types.ts
interface CalculatorField {
  id: string
  label: string
  type: 'number' | 'range' | 'select' | 'radio'
  min?: number
  max?: number
  step?: number
  defaultValue: number
  unit?: string
  options?: { label: string; value: number }[]
  format?: 'currency' | 'percent' | 'number'
}

interface CalculatorConfig {
  id: string
  fields: CalculatorField[]
  formula: (inputs: Record<string, number>) => CalculatorResult
  resultFields: ResultField[]
}

interface CalculatorResult {
  [key: string]: number
}

Now the calculator itself. Here's the config for a mortgage calculator with annuity payments:

// mortgage-calculator.ts
export const mortgageCalculator: CalculatorConfig = {
  id: 'mortgage',
  fields: [
    {
      id: 'price',
      label: 'Property price',
      type: 'number',
      min: 500_000,
      max: 100_000_000,
      step: 100_000,
      defaultValue: 5_000_000,
      format: 'currency'
    },
    {
      id: 'downPayment',
      label: 'Down payment',
      type: 'range',
      min: 10,
      max: 90,
      step: 1,
      defaultValue: 20,
      unit: '%',
      format: 'percent'
    },
    {
      id: 'rate',
      label: 'Interest rate',
      type: 'number',
      min: 0.1,
      max: 30,
      step: 0.1,
      defaultValue: 11.5,
      unit: '% per year',
      format: 'percent'
    },
    {
      id: 'term',
      label: 'Loan term',
      type: 'select',
      defaultValue: 20,
      options: [5, 10, 15, 20, 25, 30].map(y => ({ label: `${y} years`, value: y }))
    },
  ],
  formula: ({ price, downPayment, rate, term }) => {
    const principal = price * (1 - downPayment / 100)
    const monthlyRate = rate / 100 / 12
    const months = term * 12
    const payment = monthlyRate === 0 ? principal / months : principal * (monthlyRate * Math.pow(1 + monthlyRate, months)) / (Math.pow(1 + monthlyRate, months) - 1)
    const totalPayment = payment * months
    const overpayment = totalPayment - principal
    return { payment, totalPayment, overpayment, principal }
  },
  resultFields: [
    {
      id: 'payment',
      label: 'Monthly payment',
      format: 'currency',
      highlight: true
    },
    {
      id: 'totalPayment',
      label: 'Total amount paid',
      format: 'currency'
    },
    {
      id: 'overpayment',
      label: 'Overpayment',
      format: 'currency'
    },
    {
      id: 'principal',
      label: 'Loan amount',
      format: 'currency'
    },
  ],
}

React calculator component

The main component takes the config and renders fields with results. Thanks to useMemo, recalculation happens only when values change.

export function Calculator({ config }: { config: CalculatorConfig }) {
  const [values, setValues] = useState<Record<string, number>>(
    Object.fromEntries(config.fields.map(f => [f.id, f.defaultValue]))
  )
  const result = useMemo(() => {
    try {
      return config.formula(values)
    } catch {
      return null
    }
  }, [values, config])
  const handleChange = useCallback((id: string, value: number) => {
    setValues(prev => ({ ...prev, [id]: value }))
  }, [])
  return (
    <div className="calculator">
      <div className="calculator__inputs">
        {config.fields.map(field => (
          <CalculatorField
            key={field.id}
            field={field}
            value={values[field.id]}
            onChange={val => handleChange(field.id, val)}
          />
        ))}
      </div>
      {result && (
        <div className="calculator__results">
          {config.resultFields.map(rf => (
            <div key={rf.id} className={`result-item ${rf.highlight ? 'result-item--highlight' : ''}`}>
              <span className="result-item__label">{rf.label}</span>
              <AnimatedNumber value={result[rf.id]} format={rf.format} />
            </div>
          ))}
        </div>
      )}
    </div>
  )
}

Validation and animation

Validation is a common reason for rejection of a calculator. We check input immediately: if a value is invalid, we show a message and highlight the field. This reduces input errors by 40%. Number animation is implemented using requestAnimationFrame with an ease-out easing function, making changes smooth.

function CalculatorField({ field, value, onChange }: FieldProps) {
  const [rawValue, setRawValue] = useState(String(value))
  const [error, setError] = useState('')

  function handleInput(e: React.ChangeEvent<HTMLInputElement>) {
    const raw = e.target.value
    setRawValue(raw)
    const num = parseFloat(raw.replace(/\s/g, '').replace(',', '.'))
    if (isNaN(num)) {
      setError('Enter a number')
      return
    }
    if (field.min !== undefined && num < field.min) {
      setError(`Minimum: ${formatValue(field.min, field.format)}`)
      return
    }
    if (field.max !== undefined && num > field.max) {
      setError(`Maximum: ${formatValue(field.max, field.format)}`)
      return
    }
    setError('')
    onChange(num)
  }

  useEffect(() => {
    setRawValue(String(value))
    setError('')
  }, [value])

  return (
    <div className={`field ${error ? 'field--error' : ''}`}>
      <label htmlFor={field.id}>{field.label}</label>
      <input
        id={field.id}
        type="text"
        inputMode="decimal"
        value={rawValue}
        onChange={handleInput}
      />
      {field.unit && <span className="field__unit">{field.unit}</span>}
      {error && <span className="field__error">{error}</span>}
    </div>
  )
}

Number animation:

function AnimatedNumber({ value, format }: { value: number; format?: string }) {
  const [displayValue, setDisplayValue] = useState(value)
  const animationRef = useRef<number>()
  const startRef = useRef(value)
  const startTimeRef = useRef<number>()

  useEffect(() => {
    const startValue = displayValue
    startRef.current = startValue
    startTimeRef.current = undefined
    const duration = 400

    const animate = (timestamp: number) => {
      if (!startTimeRef.current) startTimeRef.current = timestamp
      const elapsed = timestamp - startTimeRef.current
      const progress = Math.min(elapsed / duration, 1)
      const eased = 1 - Math.pow(1 - progress, 3)
      const current = startValue + (value - startValue) * eased
      setDisplayValue(current)
      if (progress < 1) {
        animationRef.current = requestAnimationFrame(animate)
      }
    }

    animationRef.current = requestAnimationFrame(animate)
    return () => {
      if (animationRef.current) cancelAnimationFrame(animationRef.current)
    }
  }, [value])

  return <span className="animated-number">{formatValue(displayValue, format)}</span>
}

How to integrate the calculator with a CMS?

We prepare the config as a JSON file or via an API so that managers can update parameters without developer involvement. Here's a comparison of popular CMS platforms:

CMS Integration method Complexity
WordPress Via shortcode or Gutenberg block Low
Strapi Headless — config stored in model Medium
Drupal As a custom block with settings Medium
Sanity Connection via GROQ queries Low

In one project, integration with Strapi took 2 hours instead of the expected 2 days.

When is a server-side part needed?

If calculations must be performed on the backend (for example, to avoid exposing the formula on the frontend) or to save calculation history, we add an API on Node.js (Nest.js) or Laravel. This also allows exporting results to PDF/Excel on user request.

Common problems and how to avoid them

  • Hardcoding formulas in event handlers — complicates testing and maintenance. In one project, this cost the client 2 days of debugging.
  • Ignoring edge cases (division by zero, overflow). We check over 100 edge cases.
  • Lack of number formatting (thousand separators, currency). Violating locale reduces user trust by 20%.
  • Synchronous recalculation on every input — slows down the UI. We use useMemo, which speeds up rendering by 2 times.
  • Not accounting for locale (decimal separator, date format). Critical in international projects.

Process of work

  1. Requirements analysis. Determine fields, units, formulas, desired result format. Example: for a mortgage calculator, we fix 4 fields, ranges, and the annuity formula.
  2. Config design. Create a structure that easily adapts to changes in business logic. At most 3 iterations.
  3. UI development. Implement a responsive interface with accessibility considerations (label, aria). Test on 3 different resolutions.
  4. Testing. Check 15 edge values, typical user errors, correct formatting.
  5. Documentation and handover. Prepare a config description, setup and maintenance instructions. Hand over in a git repository.

What if the formula is complex?

Sometimes a formula contains many dependent parameters or requires iterative calculation. In such cases, we break it into sub-formulas, each tested separately. For example, for a loan calculator with differentiated payments, we extracted the calculation of each month into a separate function, simplifying debugging.

Timelines and what's included

Calculator type Timeline What's included
Simple (3–5 fields, one result) from 1 day Config, UI, validation, basic animation
Medium (dependent fields, multiple results) 2–3 days Added dependencies, URL sharing, responsive
Complex (multiple calculators, CMS management) 1–2 weeks Admin panel, reports, PDF/Excel export, full documentation

The work includes: git repository with source code, deployment instructions, 30-day warranty on bug fixes, post-launch support. We use a modern stack (React 18, TypeScript, Tailwind) and monitor Core Web Vitals (LCP < 2.5s, CLS < 0.1).

We will evaluate your project within 1 day. Order custom online calculator development today and get a reliable solution with quality guarantee. Contact us for a consultation and assessment of your requirements.