
On This Page
Creating a user-friendly currency input component can be tricky. In this guide, we'll build a reusable currency input component using shadcn-svelte and Svelte 5's new runes syntax. The component will handle formatting, proper decimal places, and currency symbols automatically.
Features
- Automatic currency formatting
- Configurable currency and locale
- Proper decimal handling
- Currency symbol display
- Full keyboard support
- Compatible with shadcn-svelte's theming
Implementation
Let's create our currency input component. We'll build it on top of shadcn-svelte's base Input component and add currency-specific functionality.
<script lang="ts">import { Input } from "$components/ui/input/index.js";
import { cn } from "$lib/utils/ui.js";
let { ref = $bindable(null), value = $bindable(""), currencyFormat = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR",
minimumFractionDigits: 2,
maximumFractionDigits: 2
}), ...restProps } = $props();
let currencySymbol = $derived.by(() => {
const formatted = currencyFormat.format(0);
return formatted.replace(/[d.,s]/g, "").trim();
});
function formatCurrency(value2) {
return currencyFormat.format(value2).replace(currencySymbol, "").trim();
}
function handleInput(event) {
const target = event.target;
const numericValue = Number(target.value.replace(/D/g, "")) / 100;
value = formatCurrency(numericValue);
}
function handleFocus(event) {
const target = event.target;
target.setSelectionRange(target.value.length, target.value.length);
}
</script>
<div class="flex-auto">
<div class="relative flex items-center">
<div class="text-muted-foreground pointer-events-none absolute left-3 flex items-center">
{currencySymbol}
</div>
<Input
bind:value
placeholder="0,00"
autocomplete="off"
maxlength={22}
inputmode="decimal"
type="text"
class={cn('pl-6', restProps.class)}
oninput={handleInput}
onfocus={handleFocus}
{ref}
{...restProps}
/>
</div>
</div>
How It Works
Let's break down the key features of our currency input component:
1. Props and Types
The component accepts standard HTML input attributes plus some custom props:
variant
: Matches shadcn's input variantsinputSize
: Controls input sizecurrencyFormat
: Allows customizing the currency format
2. Currency Formatting
We use the Intl.NumberFormat
API for robust currency formatting:
currencyFormat = new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
3. Currency Symbol Extraction
The currency symbol is automatically extracted using a derived state:
let currencySymbol = $derived.by(() => {
const formatted = currencyFormat.format(0);
return formatted.replace(/[d.,s]/g, '').trim();
});
4. Input Handling
The component handles input events to maintain proper formatting:
function handleInput(event: Event) {
const target = event.target as HTMLInputElement;
const numericValue = Number(target.value.replace(/D/g, '')) / 100;
value = formatCurrency(numericValue);
}
Usage
Here's how to use the component in your Svelte application:
<script lang="ts">import { CurrencyInput } from "$components/ui/currency-input";
let price = "";
</script>
<CurrencyInput bind:value={price} />
Custom Currency Format
You can customize the currency and locale:
<CurrencyInput
currencyFormat={new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
maximumFractionDigits: 2
})}
/>
Styling
The component inherits shadcn-svelte's theming system, so it will automatically match your application's theme. You can also customize the appearance using the class
prop:
<CurrencyInput class="w-full max-w-xs" />
Wrapping up
This currency input component provides a robust solution for handling monetary values in your Svelte applications. It combines the power of shadcn-svelte's components with proper currency formatting and user-friendly features. The component is fully typed and takes advantage of Svelte 5's new runes syntax for better reactivity handling.
Feel free to extend this component further based on your needs, such as adding validation, different currency symbols positioning, or additional formatting options.