Are you new to React.js and looking for a beginner-friendly project to boost your skills? Creating a currency converter app using React.js and CSS is a perfect choice. This project helps you understand key concepts like components, state management, and working with APIs, while also giving you a useful tool to showcase in your portfolio.
The app will also include additional features:
- Displaying country flags based on currency codes.
- A handy "swap" button to switch between the selected currencies.
Why Create a Currency Converter App in React.js?
This project is not only fun but also a great learning experience. Here's what you'll gain by building it:
Master React.js Basics
Learn how to create and manage React components.
Work with hooks like useState and useEffect to handle app logic.
API Integration
Fetch real-time exchange rates from an API.
Understand asynchronous operations and data fetching in React.
CSS for Better UI
Build a clean and responsive user interface with CSS.
Customize your design without relying on libraries like Bootstrap.
Real-Life Usability
Create a practical application that demonstrates your coding skills.
Add this project to your portfolio to impress potential employers or clients.
πProject Folder Structure
Currency_Converter/ βββ src/ β βββ Currency_App/ β β βββ component/ β β β βββ ConverterForm.jsx β β β βββ CurrencySelect.jsx β β βββ styles/ β β βββ index.css β βββ App.js β βββ index.js βββ public/ β βββ index.html βββ package.json βββ README.md
index.css
The CSS adds a modern touch with gradients and blur effects.
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap"); * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Roboto Condensed", sans-serif; } body { display: flex; align-items: center; justify-content: center; min-height: 100vh; background: rgb(131,58,180); background: linear-gradient(63deg, rgba(131,58,180,1) 0%, rgba(255,0,0,1) 50%, rgba(252,176,69,1) 100%); } #root { width: 100%; } .currency-converter { font-family: "Roboto Condensed", sans-serif; max-width: 410px; margin: 0 auto; padding: 40px 30px 50px; border-radius: 8px; backdrop-filter: blur(30px); background: rgba(2, 7, 40, 0.5); border: 1px solid rgba(255, 255, 255, 0.3); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); } .currency-converter .converter-title { color: #fff; font-size: 1.65rem; font-weight: 600; text-align: center; } .currency-converter .converter-form { margin-top: 45px; } .converter-form .form-group { display: flex; margin-bottom: 30px; flex-direction: column; } .converter-form .form-group .form-label { color: #fff; font-weight: 500; display: block; margin-bottom: 9px; font-size: 1rem; } .converter-form .form-group .form-input { outline: none; font-size: 1.1rem; padding: 0 15px; color: #fff; font-weight: 500; min-height: 48px; border-radius: 6px; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.5); } .converter-form .form-currency-group { flex-direction: row; align-items: center; justify-content: space-between; } .form-currency-group .currency-select { display: flex; padding: 0 10px; min-height: 45px; align-items: center; border-radius: 6px; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.5); } .form-currency-group .currency-select img { width: 25px; } .form-currency-group .currency-select .currency-dropdown { outline: none; border: none; background: none; color: #fff; font-size: 1rem; font-weight: 500; padding: 0 10px 0 5px; } .form-currency-group .currency-select .currency-dropdown option { color: #000; font-weight: 500; } .form-currency-group .swap-icon { height: 40px; width: 40px; cursor: pointer; display: flex; margin-top: 25px; align-items: center; justify-content: center; border-radius: 50%; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.5); transition: 0.2s ease; } .form-currency-group .swap-icon:hover { background: rgba(255, 255, 255, 0.3); } .converter-form .submit-button { width: 100%; min-height: 52px; border-radius: 6px; border: none; outline: none; font-size: 1rem; font-weight: 600; cursor: pointer; margin-top: 5px; transition: 0.2s ease; } .converter-form .submit-button.loading { opacity: 0.7; pointer-events: none; } .converter-form .submit-button:hover { background: rgba(255, 255, 255, 0.7); } .converter-form .exchange-rate-result { color: #fff; font-size: 1.1rem; font-weight: 600; text-align: center; padding: 25px 0; margin-top: 25px; border-radius: 6px; letter-spacing: 0.5px; background: rgba(255, 255, 255, 0.15); } .Last_text { color: white; text-align: center; margin-top: 15px; } @media (max-width: 640px) { body { padding: 0 10px; } .currency-converter { padding: 30px 20px 40px; } }
App.js
This is the main entry point where the ConverterForm component is rendered.
import ConverterForm from "./Currency_App/component/ConverterForm"; const App = () => { return ( <div className="currency-converter"> <h2 className="converter-title">Currency Converter</h2> <ConverterForm /> </div> ); }; export default App;
ConverterForm.jsx
import { useEffect, useState } from "react"; import CurrencySelect from "./CurrencySelect"; const ConverterForm = () => { const [amount, setAmount] = useState(100); const [fromCurrency, setFromCurrency] = useState("USD"); const [toCurrency, setToCurrency] = useState("INR"); const [result, setResult] = useState(""); const [isLoading, setIsLoading] = useState(false); // Swap the values of fromCurrency and toCurrency const handleSwapCurrencies = () => { setFromCurrency(toCurrency); setToCurrency(fromCurrency); }; // Function to fetch the exchange rate and update the result const getExchangeRate = async () => { const API_KEY = "3a2271a8d96fe3a0143bb0d5"; const API_URL = `https://v6.exchangerate-api.com/v6/${API_KEY}/pair/${fromCurrency}/${toCurrency}`; if (isLoading) return; setIsLoading(true); try { const response = await fetch(API_URL); if (!response.ok) throw Error("Something went wrong!"); const data = await response.json(); const rate = (data.conversion_rate * amount).toFixed(2); setResult(`${amount} ${fromCurrency} = ${rate} ${toCurrency}`); } catch (error) { setResult("Something went wrong!"); } finally { setIsLoading(false); } }; // Handle form submission const handleFormSubmit = (e) => { e.preventDefault(); getExchangeRate(); }; // Fetch exchange rate on initial render // eslint-disable-next-line react-hooks/exhaustive-deps useEffect(() => getExchangeRate, []); return ( <form className="converter-form" onSubmit={handleFormSubmit}> <div className="form-group"> <label className="form-label">Enter Amount</label> <input type="number" className="form-input" value={amount} onChange={(e) => setAmount(e.target.value)} required /> </div> <div className="form-group form-currency-group"> <div className="form-section"> <label className="form-label">From</label> <CurrencySelect selectedCurrency={fromCurrency} handleCurrency={(e) => setFromCurrency(e.target.value)} /> </div> <div className="swap-icon" onClick={handleSwapCurrencies}> <svg width="16" viewBox="0 0 20 19" xmlns="http://www.w3.org/2000/svg" > <path d="M19.13 11.66H.22a.22.22 0 0 0-.22.22v1.62a.22.22 0 0 0 .22.22h16.45l-3.92 4.94a.22.22 0 0 0 .17.35h1.97c.13 0 .25-.06.33-.16l4.59-5.78a.9.9 0 0 0-.7-1.43zM19.78 5.29H3.34L7.26.35A.22.22 0 0 0 7.09 0H5.12a.22.22 0 0 0-.34.16L.19 5.94a.9.9 0 0 0 .68 1.4H19.78a.22.22 0 0 0 .22-.22V5.51a.22.22 0 0 0-.22-.22z" fill="#fff" /> </svg> </div> <div className="form-section"> <label className="form-label">To</label> <CurrencySelect selectedCurrency={toCurrency} handleCurrency={(e) => setToCurrency(e.target.value)} /> </div> </div> <button type="submit" className={`${isLoading ? "loading" : ""} submit-button`} > Exchange Rate </button> <p className="exchange-rate-result"> {/* Display the conversion result */} {isLoading ? "Getting exchange rate..." : result} </p> <p className="Last_text">Designed By Sudhanshu Gaikwad</p> </form> ); }; export default ConverterForm;
CurrencySelect.jsx
const currencyCodes = [ "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", "CAD", "CDF", "CHF", "CLP", "CNY", "COP", "CRC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "FOK", "GBP", "GEL", "GGP", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "IMP", "INR", "IQD", "IRR", "ISK", "JEP", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KID", "KMF", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRU", "MUR", "MVR", "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLE", "SLL", "SOS", "SRD", "SSP", "STN", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TVD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VES", "VND", "VUV", "WST", "XAF", "XCD", "XOF", "XPF", "YER", "ZAR", "ZMW", "ZWL", ]; const CurrencySelect = ({ selectedCurrency, handleCurrency }) => { // Extract the country code from the selected currency code const countryCode = selectedCurrency.substring(0, 2); return ( <div className="currency-select"> <img src={`https://flagsapi.com/${countryCode}/flat/64.png`} alt="Flag" /> <select onChange={handleCurrency} className="currency-dropdown" value={selectedCurrency} > {currencyCodes.map((currency) => ( <option key={currency} value={currency}> {currency} </option> ))} </select> </div> ); }; export default CurrencySelect;
Looks like Currency Converter Webapp.
I hope you enjoy exploring and learning from this project! In the comments below, let me know your thoughts, suggestions, or improvements.
Happy coding! π
Top comments (0)