Skip to main content

Currency

The Currency Input component provides a user-friendly way to input monetary values with support for multiple currencies, custom validation, and full accessibility compliance.

Usage

In its most basic form, the Currency input component only needs a name to render a set of input fields for the user to enter a currency value.

<x-eloquent-ui::input.currency name="price" />

Labels

Like all other input components, the Currency component has no label by default. If you want to add a label, you can either add your own label element or use the Row component.

Because the Currency component renders three separate input fields, you can't use the for attribute in the normal way. The first of the input elements rendered is the whole number input field, so you'll have to add -whole to the for attribute value.

You should also provide an id attribute to the label element, so you can tell the Currency component which label describes it.

<label for="price-whole" id="price-label">Price</label>
<x-eloquent-ui::input.currency name="price" label-id="price-label" />

You should do the same when using the Row component. If you don't set an id attribute on the Row component, the component will use the for value as the ID suffixed by -label. So in the example below, it would be "price-whole-label".

<x-eloquent-ui::form.row for="price-whole" id="price-label" label="Price">
<x-eloquent-ui::input.currency name="price" label-id="price-label" />
</x-eloquent-ui::form.row>

Currencies

There are three distinct ways in which you can use the Currency component: without currency, with a single currency, or with multiple currencies.

Without currency

This is the simplest behaviour. You don't need to add anything to the component to use it without currency. Not providing a currency will render the component without currency options. The {{ name }}-currency hidden field will be empty in this case upon form submission.

With a single currency

If you provide a single currency value to the component, it will use a prefix for the component to show the currency. It will also add this value to the {{ name }}-currency hidden field, so you can get the currency value from the request upon submission.

You can provide the currency value through the currency attribute, or by using the currency slot.

<x-eloquent-ui::input.currency name="price" currency="USD" />

<x-eloquent-ui::input.currency name="price" currency="" />

With multiple currencies

If you provide an array of currency values to the component, it will render a dropdown menu with the available currencies. The dropdown menu will be rendered in front of the input fields, and changing the currency will update the {{ name }}-currency hidden field accordingly. It will also broadcast the CurrencyChanged event on the JavaScript side when the currency changes, and it also updates the accessibility labels of the input fields and announces the new currency to screen readers.

You can provide the currency array through the currencies attribute. You can also provide a selected currency value through the currency attribute.

The currency array must be a 'key' => 'value' array, where the key is the currency value that will be set in the {{ name }}-currency hidden field, and the value is the currency name that should be shown in the dropdown menu.


$currencies = [
'EUR' => 'Euro',
'USD' => 'US Dollar',
// Other currencies...
];

<x-eloquent-ui::input.currency name="price" :currencies="$currencies" currency="EUR" />
Validation of currencies

If you provide an array of currencies to the component, you should provide the same array to the validation rule as well to make sure the frontend and backend validation logic matches.

Optional attributes

todo describe the other attributes

Features

The Currency component supports the following features.

Tabindex

The currency input component can be focused using the tabindex attribute. Keep in mind that the currency component consists of two or three input fields, depending on whether the currency is provided, so the tabindex for the next field will have to account for this.

If you provide a currency to the component (either a single currency or a list of available currencies), the currency field will have the tabindex provided, the whole input field will have the tabindex provided plus one, and the cent input field will have the tabindex provided plus two. In this case the next input element should have a tabindex of {{ $tabindex + 3 }}.

If you don't provide a currency to the component, the whole input field will have the tabindex provided and the cent input field will have the tabindex provided plus one. In this case the next input element should have a tabindex of {{ $tabindex + 2 }}.

Usability

When typing a number into the whole number field, pressing either . or , will automatically move focus to the cent field. You can disable this behaviour be setting the focus-switch property to false directly on the component or globally in your config file.

Copy/paste support

Pasting any number value into the whole number or cent field will automatically format it correctly and divide it into whole and cents. It can handle both . and , as decimal separators, and ., ,, (space) and _ as a thousand separators.

Backend logic

Validation

Because the component internally renders multiple separate input fields, you can't use the default Laravel validation rules to validate the currency value. Instead, you'll need to use the provided Currency validation rule.

<?php

declare(strict_types=1);

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use BrickNPC\EloquentUI\Http\Rules\Currency;

class StoreOrderRequest extends FormRequest
{
public function rules(): array
{
return [
'price' => [new Currency(
required: true,
min: 0,
max: 9999.99,
currencies: ['EUR', 'USD'],
)],
];
}
}

All properties of the Currency rule are optional. If no properties are provided, the rule will just validate whether the value is a valid currency amount.

Custom validation

For more complex validation logic, you will have to implement your own validation logic. If you do so, please consider opening a pull request to add it to the package.

Getting the value from the request

To help you get the currency value from the request, the Currency input component comes with a HasCurrencyInput trait. This trait adds a currency method to your request class that returns the currency value as a BrickNPC\EloquentUI\ValueObjects\CurrencyInput object.

<?php

declare(strict_types=1);

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use BrickNPC\EloquentUI\Http\Rules\Currency;
use BrickNPC\EloquentUI\Http\Traits\HasCurrencyInput;

class StoreOrderRequest extends FormRequest
{
use HasCurrencyInput;

public function getPrice(): ?int
{
return $this->currency('price')?->amountInCents;
}
}

The CurrencyInput has the following public properties that can be accessed:

PropertyTypeDescription
$wholeintThe amount before the decimal separator as an int.
$centsintThe amount of cents as an int.
$amountfloatThe total amount as a float.
$amountInCentsintThe total amount in cents as an integer.
currencystring|nullThe currency selected.

Advanced usage

Internally, the Currency input component is split into three separate inputs: a hidden text field for the currency, a number field for the number of cents, and a number field for the whole number. They are added to the DOM with the following names and ID's:

  • input type="number" name="{{ $name }}-whole" id="{{ $name }}-whole"
  • input type="number" name="{{ $name }}-cents" id="{{ $name }}-cents"
  • input type="hidden" name="{{ $name }}-currency" id="{{ $name }}-currency"

You can get these inputs from the request manually by using their names and use them in your own validation logic. You can also write custom JavaScript or CSS code to handle custom logic and styling by using these input names/ID's directly.

A note about validation

If you want to implement your own validation logic, make sure to account for leading zeros in the cents input field. All values in the cent field are left padded with zeros until they are two digits long. Some of Laravel's numeric validation rules like integer will not work correctly with this input, flagging any values with leading zeros as invalid.

Data attributes

Like with all other components, the Currency component supports custom data attributes. Adding a data- attribute to the Currency component will add it to the topmost HTML element of the component, which is the input-group element.

<div {{ $attributes->merge(['class' => 'input-group has-validation']) }}>
The component
</div>