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)