FX Converter
Two linked amount and currency fields: type what you send or what arrives, with the fee, a swap and a guaranteed rate.
c2-fx-converter quotes a currency transfer the way Wise and Revolut do: the reader types what they send or what the recipient gets, and the other amount is computed from the rate, after the fee. A swap button exchanges the currencies, and a guaranteed rate counts down beside the rate line, then asks for a new one.
Import
import '@c2n/components/fx-converter'Usage
- − 4.13 EURFee
- = 995.87 EURAmount converted >
- × 1.0842Exchange rate
- 1 GBP = 1.2741 USDExchange rate
Amounts and the rate
Amounts are integers in minor units, as in c2-money-input: amount="100000" in EUR is €1,000.00, and no amount passes through floating point. Only rate is a float: 1 unit of from buys rate units of to.
- With
fixed="from"(the default), the recipient gets(amount − fee) × rate, rounded to their currency’s minor unit. - Typing in the lower field switches to
fixed="to": the amount sent becomesamount ÷ rate + fee, rounded up so the recipient gets at least what was typed. The label reads “Recipient gets exactly”. feeis in minor units offrom. Set, it draws the fee and “amount converted” lines; unset, the rate line reads “1 GBP = 1.2741 USD”.maxcaps the amount sent, with an error under the upper field.fromAmount,toAmountandvalueread the result, andinput/changecarry it as{ from, to, fromAmount, toAmount, fixed, rate }.
Quotes from your server
The component never fetches a rate. It tells the app when it needs one:
const fx = document.querySelector('c2-fx-converter')!
async function quote() {
const { rate, fee, expiresAt } = await fetchQuote(fx.from, fx.to)
Object.assign(fx, { rate, fee: String(fee), rateExpires: expiresAt })
}
fx.addEventListener('currency-change', quote) // a new pair
fx.addEventListener('swap', quote) // the pair reversed: 1 ÷ rate is shown as indicative until then
fx.addEventListener('rate-refresh', quote) // the reader asked for a new rate after it expiredrate-expires takes an ISO time or epoch milliseconds. While it runs, the rate line counts down (“Guaranteed for 24s”) with a ring; when it runs out the computed amount dims, rate-expire fires, and a “New rate” button takes the swap button’s place. Setting rate or rate-expires again clears it.
Accessibility
Each amount field is named by its label, and the currency pickers are the money inputs’ own. Once typing pauses, a polite live region reads the computed amount (“Recipient gets 1,079.72 USD”), and it says when the rate expires. The countdown ring is hidden from assistive technology; the text beside it carries the time.