Skip to content
Devix Open Source

Guide

React, Vue, Svelte and a plain page

React

import { AmountInput } from '@devix-labs/amount-input/react';

<AmountInput
  currency="AED"
  name="total"
  value={total}                      // a string
  onChange={(decimal) => setTotal(decimal)}
/>

value and onChange are decimal strings. There is no number in the API at all, which is the point — and it is why there is nothing here corresponding to vue-currency-input #346, "Drop MAX_SAFE_INTEGER limitation".

The widget owns the field's text and React never writes value to the DOM, so a re-render while someone is typing cannot move the caret.

react-hook-form

<Controller
  name="total"
  control={control}
  render={({ field }) => (
    <AmountInput currency="AED" value={field.value} onChange={field.onChange} onBlur={field.onBlur} />
  )}
/>

Vue

<script setup>
import { ref } from 'vue';
import { AmountInput } from '@devix-labs/amount-input/vue';

const total = ref('');
</script>

<template>
  <AmountInput v-model="total" currency="AED" name="total" />
</template>

Svelte

<script>
  import { amountInput } from '@devix-labs/amount-input/svelte';

  let total = '';
</script>

<input use:amountInput={{ currency: 'AED', onChange: (v) => (total = v.decimal) }} name="total" />

A web component

<script type="module" src="https://devix.pk/cdn/oss/amount-input@1.0.0/element.js"></script>

<dx-amount-input currency="KWD" name="total" show-currency></dx-amount-input>

Attributes: currency, locale, value, typing, min, max, show-currency, allow-negative, accounting. It fires change and commit, and exposes .value, .minor and .instance.

Wrap a field you already have to keep its label, attributes and tab order:

<label for="total">Total</label>
<dx-amount-input currency="AED">
  <input id="total" name="total">
</dx-amount-input>

Laravel

The hidden-field behaviour means your controller never knows a widget was involved — it receives 1234.56, not AED 1,234.56:

<form method="post">
  @csrf
  <input name="total" id="total" value="{{ old('total', $invoice->total) }}">
</form>

<script type="module">
  import { createAmountInput } from '/cdn/oss/amount-input@1.0.0/index.js';

  createAmountInput(document.querySelector('#total'), {
    currency: @json($invoice->currency),
    locale: @json(app()->getLocale()),
  });
</script>
$request->validate(['total' => ['required', 'decimal:0,2', 'min:0']]);

Store it in an integer column of minor units, or a decimal(19,4). Not a float, and not a double — which is the same argument as the rest of this page, one layer down.

Enhancing fields you already have

document.querySelectorAll('[data-amount]').forEach((field) => {
  createAmountInput(field, { currency: field.dataset.amount });
});
<input name="subtotal" data-amount="AED">
<input name="deposit"  data-amount="KWD">
Updated 15 Sep 2026