svelte-currency
v0.0.8
Published
A svelte currency input action with optimized UX
Downloads
16
Maintainers
Readme
svelte-currency
A svelte currency input action with optimized UX
While looking for a currency input component I found a number of issues with existing solutions:
- included the currency symbol inside the input
- allowed addional inputs beyond the decimal digit limit (often corrupting the entered value)
- outright handle inputs wrong (e.g. entering "1.23" results in "13")
- inputs were left formatted, when numbers are typically right aligned
- formatting wasn't applied until the input loses focus
- cursor position jumped around especially when dealing with grouping
- showed input spinners / wrong keyboard on mobile
This is my attempt to create the currency input I wanted. It has the following features:
- ✅ Tiny 2kb size, as a Svelte
use:action
(also usable without Svelte!) - ✅ Automatically configures the input type and inputmode attributes for best experience
- ✅ Pass the ISO currency code to use, support popular crypto-currencies such as BTC
- ✅ Automatically set an appropriate placeholder based on the currencies decimal points
- ✅ Handle locale formatting, specifically the opposite decimal point and grouping symbols in Europe
- ✅ Works with TailwindCSS / TailwindUI currency input layout (see example)
Usage
Install using your package manager of choice, which should be pnpm
:
pnpm i -D svelte-currency
Import it into the component you want to use it:
<script lang="ts">
import { currency } from 'svelte-currency'
</script>
Add it to an HTML input element with the use:
syntax:
<input id="price" name="price" use:currency={{ currency: 'USD' }} />
Set the currency to have the input formatted appropriately. By default it will use the browser locale but you can override that by passing it in, and also set the decimals to use if dealing with non-traditional currencies (e.g. bitcoin)
<input id="price" name="price" use:currency={{ currency: 'BTC', locale: 'en', digits: 8 }} />
Vanilla JS
As it's a Svelte Action, there aren't really any dependencies on Svelte itself - you can apply it to any HTML Input manually:
const input: HTMLInputElement = document.querySelector('input')!
const action = currency(input, { currency: 'USD' })
// update the options:
action.update({ currency: 'CAD' })
// remove it:
action.destroy()
Output Value
Because the input value is the formatted string, you may have issues if you try to convert it to a numeric value using parseFloat
because that doesn't handle group separators or decimal commas. Use the .valueAsNumber
property of the input to access the numberic value as a number that has been pre-normalized / parsed for you.
Example
An empty input for USD with an English locale will show a placeholder of 0.00
, a European local would show 0,00
Entering digits will fill them ahead of the decimal point, with the cursor positioned before it. The current cursor position is indicated with |
:
| Key Entry | Value | European |
| --------- | ---------------: | ---------------: |
| Enter 1
| 1\|.00
| 1\|,00
|
| Enter 2
| 12\|.00
| 12\|,00
|
| Enter 3
| 123\|.00
| 123\|,00
|
| Enter 4
| 1,234\|.00
| 1.234\|,00
|
| Enter 5
| 12,345\|.00
| 12.345\|,00
|
| Enter 6
| 123,456\|.00
| 123.456\|,00
|
| Enter 7
| 1,234,567\|.00
| 1.234.567\|,00
|
| Enter .
| 1,234,567.\|00
| 1.234.567,\|00
|
| Enter 8
| 1,234,567.8\|0
| 1.234.567,8\|0
|
| Enter 9
| 1,234,567.89\|
| 1.234.567,89\|
|
The decimal point can be entered at any point to position the input cursor to after it which feels natural.
Once the input is filled, no more key presses will be allowed - the decimals won't be rounded as a result and the cursor won't jump to the main unit input as happens on many other currency inputs.
Pressing +
or -
at any point will change the sign of the input (-
if negative will toggle it)
Backspace
will remove digits to the left of the cursor, moving the cursor if it's to the right of the decimal point and pulling the input right when to the left. The decimal point is jumped as are any group separators.
| Key Entry | Value | European |
| ----------- | ---------------: | ---------------: |
| | 1,234,567.89\|
| 1.234.567,89\|
|
| Backspace
| 1,234,567.8\|0
| 1.234.567,8\|0
|
| Backspace
| 1,234,567.\|00
| 1.234.567,\|00
|
| Backspace
| 123,456\|.00
| 123.456\|,00
|
| Backspace
| 12,345\|.00
| 12.345\|,00
|
| Backspace
| 1,234\|.00
| 1.234\|,00
|
| Backspace
| 123\|.00
| 123\|,00
|
| Backspace
| 12\|.00
| 12\|,00
|
| Backspace
| 1\|.00
| 1\|,00
|
| Backspace
| 0.00\|
| 0,00\|
|
Delete
will delete the digit to the right of the cursor, jumping grouping symbols and moving to the right when past the decimal point.
Entering grouping character will be ignored. ArrowLeft
and ArrowRight
change the cursor position.
Pasted values will be parsed and formatted and the cursor positioned at the end.
Selecting text and entering any digit or pressing Backspace
or Delete
will replace or remove the selected characters, positioning the cursor to the right of the selection or the decimal point.