Back to Documentation

Build a Currency Converter App

Complete step-by-step tutorial to build a professional currency converter using React and the FXRateSync API

Beginner Friendly30-45 minutesReact + TypeScript

What You'll Learn

  • Setting up React with TypeScript
  • Integrating FXRateSync API
  • Real-time currency conversion
  • Error handling best practices
  • Professional UI with Tailwind CSS
  • Production deployment ready

Prerequisites

  • • Basic knowledge of React and TypeScript
  • • Node.js 16+ installed on your machine
  • • FXRateSync API key (free tier available)
  • • Code editor (VS Code recommended)

Step 1: Project Setup

Let's start by creating a new React project with TypeScript and installing the necessary dependencies.

# Create a new React app with TypeScript
npx create-react-app currency-converter --template typescript
cd currency-converter

# Install additional dependencies
npm install axios tailwindcss
npx tailwindcss init

Step 2: API Service Setup

Create a service to handle API calls to FXRateSync. This keeps your API logic organized and reusable.

// src/services/currencyService.ts
import axios from 'axios'

const API_BASE_URL = 'https://api.fxratesync.io/v1'
const API_KEY = process.env.REACT_APP_FX_API_KEY

export interface ConversionResult {
  from: string
  to: string
  amount: number
  converted_amount: number
  rate: number
  timestamp: string
}

export class CurrencyService {
  private static instance: CurrencyService
  
  static getInstance(): CurrencyService {
    if (!CurrencyService.instance) {
      CurrencyService.instance = new CurrencyService()
    }
    return CurrencyService.instance
  }

  async convertCurrency(
    from: string, 
    to: string, 
    amount: number
  ): Promise<ConversionResult> {
    try {
      const response = await axios.get(
        `${API_BASE_URL}/convert?from=${from}&to=${to}&amount=${amount}`,
        {
          headers: {
            'X-API-Key': API_KEY
          }
        }
      )
      return response.data
    } catch (error) {
      throw new Error('Failed to convert currency')
    }
  }

  async getSupportedCurrencies(): Promise<string[]> {
    // For this tutorial, we'll use a static list
    return ['USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD', 'CHF', 'CNY']
  }
}

Step 3: Main Component

Now let's create the main currency converter component with a clean, professional interface.

// src/components/CurrencyConverter.tsx
import React, { useState, useEffect } from 'react'
import { CurrencyService, ConversionResult } from '../services/currencyService'

const CurrencyConverter: React.FC = () => {
  const [fromCurrency, setFromCurrency] = useState('USD')
  const [toCurrency, setToCurrency] = useState('EUR')
  const [amount, setAmount] = useState(100)
  const [result, setResult] = useState<ConversionResult | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [currencies, setCurrencies] = useState<string[]>([])

  const currencyService = CurrencyService.getInstance()

  useEffect(() => {
    loadCurrencies()
  }, [])

  const loadCurrencies = async () => {
    try {
      const supportedCurrencies = await currencyService.getSupportedCurrencies()
      setCurrencies(supportedCurrencies)
    } catch (err) {
      setError('Failed to load currencies')
    }
  }

  const handleConvert = async () => {
    if (amount <= 0) {
      setError('Amount must be greater than 0')
      return
    }

    setLoading(true)
    setError(null)

    try {
      const conversionResult = await currencyService.convertCurrency(
        fromCurrency,
        toCurrency,
        amount
      )
      setResult(conversionResult)
    } catch (err) {
      setError('Conversion failed. Please try again.')
    } finally {
      setLoading(false)
    }
  }

  const swapCurrencies = () => {
    setFromCurrency(toCurrency)
    setToCurrency(fromCurrency)
    setResult(null)
  }

  return (
    <div className="max-w-2xl mx-auto p-6 bg-background rounded-2xl shadow-xl">
      <h1 className="text-3xl font-bold text-center text-foreground mb-8">
        Currency Converter
      </h1>

      <div className="space-y-6">
        {/* Amount Input */}
        <div>
          <label className="block text-sm font-medium text-foreground mb-2">
            Amount
          </label>
          <input
            type="number"
            value={amount}
            onChange={(e) => setAmount(Number(e.target.value))}
            className="w-full px-4 py-3 border border-border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
            placeholder="Enter amount"
          />
        </div>

        {/* Currency Selectors */}
        <div className="grid grid-cols-1 md:grid-cols-3 gap-4 items-end">
          <div>
            <label className="block text-sm font-medium text-foreground mb-2">
              From
            </label>
            <select
              value={fromCurrency}
              onChange={(e) => setFromCurrency(e.target.value)}
              className="w-full px-4 py-3 border border-border rounded-lg focus:ring-2 focus:ring-blue-500"
            >
              {currencies.map(currency => (
                <option key={currency} value={currency}>{currency}</option>
              ))}
            </select>
          </div>

          <div className="flex justify-center">
            <button
              onClick={swapCurrencies}
              className="px-4 py-2 text-primary hover:bg-primary/10 rounded-lg transition-colors"
            >
              ⇄ Swap
            </button>
          </div>

          <div>
            <label className="block text-sm font-medium text-foreground mb-2">
              To
            </label>
            <select
              value={toCurrency}
              onChange={(e) => setToCurrency(e.target.value)}
              className="w-full px-4 py-3 border border-border rounded-lg focus:ring-2 focus:ring-blue-500"
            >
              {currencies.map(currency => (
                <option key={currency} value={currency}>{currency}</option>
              ))}
            </select>
          </div>
        </div>

        {/* Convert Button */}
        <button
          onClick={handleConvert}
          disabled={loading}
          className="w-full bg-primary hover:bg-primary/90 disabled:opacity-50 text-background font-semibold py-3 px-6 rounded-lg transition-colors"
        >
          {loading ? 'Converting...' : 'Convert Currency'}
        </button>

        {/* Results */}
        {result && (
          <div className="bg-success/10 border border-success/30 rounded-lg p-6">
            <div className="text-center">
              <div className="text-3xl font-bold text-success-foreground mb-2">
                {result.converted_amount.toFixed(2)} {result.to}
              </div>
              <div className="text-sm text-success">
                {result.amount} {result.from} = {result.converted_amount.toFixed(2)} {result.to}
              </div>
              <div className="text-xs text-success mt-2">
                Rate: {result.rate.toFixed(4)} • {new Date(result.timestamp).toLocaleString()}
              </div>
            </div>
          </div>
        )}

        {/* Error Display */}
        {error && (
          <div className="bg-destructive/10 border border-destructive/30 rounded-lg p-4 text-destructive-foreground">
            {error}
          </div>
        )}
      </div>
    </div>
  )
}

export default CurrencyConverter

Step 4: Environment Configuration

Create a `.env` file in your project root to store your API key securely.

# .env
REACT_APP_FX_API_KEY=your_api_key_here

Security Note: Never commit your `.env` file to version control. Add it to your `.gitignore` file to keep your API key secure.

Step 5: Testing & Deployment

Test your application locally and prepare it for deployment.

# Test locally
npm start

# Build for production
npm run build

# Deploy to Netlify, Vercel, or your preferred hosting

Next Steps

Enhance Your App

  • • Add historical rate charts
  • • Implement rate alerts
  • • Add favorite currency pairs
  • • Include currency trend indicators

Ready to Deploy?

Get your free API key and start building amazing currency applications

Get Free API Key