Skip to content
Components, switch product

Currency

<gui-currency> is a field for an amount of money. It renders a native <input type="number"> with its label, hint and errors, and shows the amount formatted in its currency, such as $1,250.00.

Code of the example above
CurrencyBasic.tsx
import { GuiCurrency } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function CurrencyBasic() {
return <GuiCurrency label="Budget" value={1250} />;
}

The element’s entry point is @golemui/gui-components/currency, which registers <gui-currency> and nothing else. To install the package and load the stylesheet, see Installation.

The @golemui/gui-components/react components have typed props and an on* prop for each event. React 18 or later.

BudgetField.tsx
import { useState } from 'react';
import { GuiCurrency } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function BudgetField() {
const [budget, setBudget] = useState(0);
return (
<GuiCurrency
label="Budget"
name="budget"
currency="EUR"
value={budget}
onGuiChange={(event) => setBudget(event.detail.value ?? 0)}
/>
);
}

The value is a plain number, such as 1250.5, or undefined while the field is empty. The snippets fall back to 0 when the user clears the field.

Properties

Property Type Default Description
localeId attribute locale-id string – BCP 47 locale for formatting and parsing, such as en-US or es.
value number | null – The amount, or undefined when empty.
currency string – ISO 4217 currency code, such as USD or EUR.
step number – The step of the ArrowUp and ArrowDown keys.
maximumFractionDigits attribute maximum-fraction-digits number – Maximum number of decimals shown.
minimumFractionDigits attribute minimum-fraction-digits number – Minimum number of decimals shown.
icon string – Icon class name shown inside the control, for example from an icon font.
placeholder string – Text shown while the control is empty.
autocomplete string – The autocomplete hint passed to the inner native control.
uid string – The id of the element's control. The ids of its label, hint and errors derive from it. Optional: when it is not set, the element generates one from its tag name and a page-wide counter, e.g. gui-textinput-3. Generated ids depend on creation order, so a server-rendered element must set uid or its ids will not match after hydration.

Form control properties

Every field has these, from the base class of the form controls.

Property Type Default Description
name string – The name the value is submitted under. Without it the element stays out of its form. Reflected, like a native control's: the form reads a single value's name from the attribute.
label string – The visible label, which also names the control for assistive technology. Without one the control has no accessible name; the date, time, range, tags and file fields warn about it in development builds.
hint string – Help text shown under the label and announced as the control's description.
errors string[] [] Error messages to show, typically from your own validation. They show as soon as they are set, unless touched is false.
touched boolean – Whether the user has interacted with the control. Leave it unset unless you validate on interaction: false holds errors back until it becomes true.
required boolean false The control needs a value: it is marked as required and, with a name, blocks submission.
readOnly attribute readonly boolean – The value can be read and focused but not changed.
disabled boolean – Disabled by its own attribute or by a disabled <fieldset> around it. Setting the property sets the attribute, like a native control's.
form read-only, no attribute HTMLFormElement | null – The <form> the element belongs to, if any.
validity read-only, no attribute ValidityState – The element's validity, like a native control's.
validationMessage read-only, no attribute string – The message the browser shows for an invalid value.

Methods

Method Description
checkValidity(): boolean –
reportValidity(): boolean –

Events

Every event bubbles and is composed, so you can listen on any ancestor.

Event Description
gui-input The user changed the value. detail.value is the new value.
gui-change The user committed the text, on blur or Enter. detail.value is the value.
gui-blur Focus left the control.

currency takes an ISO 4217 code, USD by default. locale-id takes a BCP 47 locale, en by default, and sets the symbol’s place and the separators. The field shows two decimals; for a currency without cents, set maximum-fraction-digits="0". minimum-fraction-digits sets the fewest decimals shown.

Code of the example above
CurrencyCurrencies.tsx
import { GuiCurrency } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function CurrencyCurrencies() {
return (
<div className="gui-grid gui-grid--row">
<div className="gui-grid__cell">
<GuiCurrency
label="Price"
currency="USD"
localeId="en-US"
value={1299.5}
/>
</div>
<div className="gui-grid__cell">
<GuiCurrency
label="Preis"
currency="EUR"
localeId="de-DE"
value={1299.5}
/>
</div>
<div className="gui-grid__cell">
<GuiCurrency
label="価格"
currency="JPY"
localeId="ja-JP"
maximumFractionDigits={0}
value={189000}
/>
</div>
</div>
);
}

Focus a field to edit it. While it has focus, the field shows the plain number to type in, and the formatted amount moves up over its top border. It formats the amount again as the user types, and when they leave.

↑ and ↓ add or take away step, 1 by default. The field has no bounds: the arrow keys go below zero too.

Code of the example above
CurrencyStep.tsx
import { GuiCurrency } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function CurrencyStep() {
return (
<GuiCurrency
label="Monthly donation"
currency="GBP"
localeId="en-GB"
step={5}
value={20}
hint="Arrow keys change it by £5."
/>
);
}

The element has no minimum or maximum. Check the amount in your own validation and set errors, for example from a gui-change listener. Its detail.value is the plain number, or undefined for an empty field.

Code of the example above
CurrencyValidation.tsx
import { useState } from 'react';
import { GuiCurrency } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function CurrencyValidation() {
const [errors, setErrors] = useState<string[]>([]);
return (
<GuiCurrency
id="tip"
label="Tip"
currency="EUR"
localeId="es-ES"
hint="Between 1 € and 50 €."
errors={errors}
onGuiChange={(event) => {
const value = event.detail.value;
const valid =
value === undefined || (value !== null && value >= 1 && value <= 50);
setErrors(valid ? [] : ['Enter an amount between 1 € and 50 €.']);
}}
/>
);
}

icon, placeholder, hint, disabled and readonly work as on the text input.

With a name, <gui-currency> submits the plain number as text under that name, such as 42.5: no symbol, no separators and no currency code. Submit the currency along with it, in a field of its own, if your server needs it. An empty field submits nothing, and required blocks an empty submit.

step is only the step of the arrow keys: any amount, cents included, is valid.

Code of the example above
CurrencyNativeForm.tsx
import { useState, type SubmitEvent } from 'react';
import {
GuiButton,
GuiCurrency,
GuiTextinput,
} from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function CurrencyNativeForm() {
const [result, setResult] = useState('');
const onSubmit = (event: SubmitEvent<HTMLFormElement>) => {
event.preventDefault();
const data = Object.fromEntries(new FormData(event.currentTarget));
setResult(`Submitted ${JSON.stringify(data)}`);
};
return (
<form id="expense" onSubmit={onSubmit}>
<div className="gui-grid gui-grid--row">
<div className="gui-grid__cell">
<GuiTextinput label="Description" name="description" required />
</div>
<div className="gui-grid__cell">
<GuiCurrency
label="Amount"
name="amount"
currency="EUR"
localeId="fr-FR"
required
/>
</div>
</div>
<GuiButton type="submit" label="Add expense" />
<p id="expense-result" role="status">
{result}
</p>
</form>
);
}

How the elements submit, validate and reset is in Native forms.

<gui-currency> renders into the light DOM, so you can style every part with plain CSS. These are the parts and their public classes:

gui-currency
<gui-currency class="gui-field">
<label class="gui-label" for="budget" id="budget_label">
<span class="gui-label__text">Budget</span>
</label>
<div class="gui-widget">
<input
type="number"
inputmode="decimal"
id="budget"
class="gui-widget-input gui-currency--icon"
/>
<span
aria-hidden="true"
class="gui-currency__format-value gui-currency__format-value--icon"
>$1,250.00</span
>
<span
class="gui-widget-icon icon-wallet"
data-icon="icon-wallet"
aria-hidden="true"
></span>
</div>
<div
class="gui-validator gui-validator--empty"
id="budget_errors"
role="alert"
></div>
</gui-currency>
ClassPart
gui-fieldThe element itself. Lines its parts up with the fields next to it in a gui-grid row.
gui-labelThe label, with the text and the hint.
gui-label__textThe label text and the required marker.
gui-widget-hintThe hint.
gui-widgetThe box around the control.
gui-widget-inputThe <input>, the part that looks like a field. Its text is transparent until it has focus.
gui-currency--iconOn the <input> when there is an icon: it makes room for it.
gui-currency__format-valueThe formatted amount, over the input. Only while there is an amount.
gui-currency__format-value--iconOn the formatted amount when there is an icon.
gui-widget-iconThe icon, with your icon classes.
gui-validatorThe errors container. It is always there, so the alert role announces new errors.
gui-validator--emptyOn the errors container while there are no errors.
gui-validator__errorOne error message.

The ids derive from uid, or from a generated id such as gui-currency-3 when you don’t set one. Select by class or by tag, not by id.

The field reads these design tokens. Set them on :root to change every field, or on any element to change the fields inside it:

TokenWhat it styles
--gui-widget-sizeThe height of the field, and the size of the icon.
--gui-radius-mdThe corner radius.
--gui-bg-surfaceThe field’s background, and the formatted amount’s.
--gui-border-defaultThe border.
--gui-text-defaultThe amount, the label and the icon.
--gui-font-familyThe font.
--gui-font-smThe text size of the label, the field and the formatted amount.
--gui-font-xsThe text size of the hint and the errors.
--gui-text-secondaryThe hint.
--gui-space-10The room for the icon.
--gui-border-focusThe border while focused.
--gui-shadow-focusThe focus ring.
--gui-intent-errorThe border and the messages when there are errors, and the formatted amount of a focused field with errors.
--gui-shadow-focus-errorThe focus ring when there are errors.
--gui-bg-disabledThe background when disabled.
--gui-text-disabledThe text when disabled.
--gui-space-1The space between the label, hint and errors.

To restyle beyond the tokens, see Overriding styles; for dark mode and the Clay theme, see Themes and dark mode.

  • Name. The label names the field. Without one the field has no accessible name.
  • The amount. The formatted amount is hidden from assistive technology: screen readers read the plain number in the input, such as 1250, without the currency. Put the currency in the label or the hint, such as “Budget (EUR)”.
  • Description. The hint is the field’s description, through aria-describedby.
  • Errors. While errors show, the input has aria-invalid="true" and points at them with aria-errormessage, and screen readers announce new errors as they appear.
  • Required. required sets aria-required; the visual marker is hidden from screen readers.
  • Keyboard on phones. inputmode="decimal" opens a keypad with a decimal point.
KeyAction
TabMoves focus to the field, and away from it.
↑Adds step and fires gui-input and gui-change.
↓Takes away step and fires gui-input and gui-change.
EnterCommits a typed amount, as leaving the field does, and fires gui-change.
Number keysType digits, a decimal separator, a sign or an exponent. Other characters are dropped.

What every element shares, such as translating the browser messages, is in Accessibility.