Drupal is a registered trademark of Dries Buytaert

Makes entering numbers with units (e.g. currency) a breeze! This module provides a widget that automatically formats numbers as you type, adding currency symbols, thousand separators, and more, based on your language settings.

Features

The Formatted Number Input module enhances Drupal's core number fields (Number, Decimal, Float) by providing an intuitive and structured data entry experience. It is ideal for any situation where you need users to input numbers in a specific format, such as prices, measurements, or scores.
The module's functionality is broken into two main parts: the Input Widget (for data entry forms) and the Display Formatter (for showing the value to site visitors).

The "Formatted Number Input" Widget

This widget provides live, real-time input masking powered by the excellent AutoNumeric.js library.

Its behavior can be fine-tuned with a comprehensive set of options:

Global Behavior Settings:
These settings control the overall user experience of the input field.

  • Placeholder: Set custom placeholder text that appears when the field is empty.
  • Rounding Method: Choose from nine different mathematical rounding methods, including Round-Half-Up, Round-Half-Even (Banker's Rounding), and rounding for specific currencies (CHF).
  • Formula Mode: Allow users to perform simple calculations directly in the field (e.g., entering 15*3 will result in 45).
  • Select Number Only: When a user clicks or highlights the field, you can specify whether only the number itself is selected, or the entire formatted string (including the currency symbol).
  • Select on Focus: Automatically select the entire field contents when the user tabs into it, making it easy to replace the value.
  • Style Rules Preset: Automatically apply a CSS class to the field based on its value. The module includes default CSS for the following presets:
    • Positive / Negative / Zero
    • 0-100 Color Range (4 Steps)
    • Even / Odd
    • Small Range Around Zero (-1 to 1)
  • Symbol Placement for Bracketed Negatives: When using brackets for negative numbers, you can choose if the currency symbol appears inside ($123.45) or outside $(123.45) the brackets on the display formatter.

Per-Language Formatting Settings:
For each language on your site, you can define a unique set of formatting rules. This ensures numbers are always presented correctly for the target audience.

  • Unit or Currency Symbol: The symbol to be used (e.g., $, €, kg, £).
  • Symbol Placement: Whether the symbol should appear before the number (Prefix) or after it (Postfix).
  • Thousand Separator: The character used to separate groups of thousands (e.g., a comma , or a period .).
  • Decimal Separator: The character used for the decimal point (e.g., a period . or a comma ,).
  • Sign Placement: Control the exact position of a positive or negative sign (e.g., -€100, €-100, €100-).
  • Negative Sign Character: Choose the character for negative numbers (e.g., hyphen - or en-dash –).
  • Negative Value Brackets: Opt to wrap negative numbers in brackets instead of using a sign. You can choose from (...), [...], {...}, or <...>.
  • Positive Sign Character: The character to use for positive numbers (e.g., +).
  • Show Positive Sign: Choose whether to explicitly show the sign for positive numbers (e.g., +100).

The "Formatted as in input widget" Display Formatter

This formatter is the second half of the module and is designed to be as simple as possible. Its sole purpose is to read the settings you already configured on the input widget and apply them for display. Just like the widget, the formatter is language-aware; it will automatically apply the correct currency, symbols, and separators for the language in which the content is being viewed.

This creates a true "what you see is what you get" experience and ensures your data entry rules and display rules are always perfectly in sync.

Post-Installation

Once the module is installed (along with its required library, see below), you first configure the input widget for a number field.

  1. Navigate to the Manage form display page for any entity (e.g., a Content Type). For a content type like "Article", you would go to Structure > Content types > Article > Manage form display.
  2. Find the number field you wish to configure (e.g., field_price).
  3. In the "Widget" column, select "Formatted Number Input" from the dropdown list.
  4. Click the gear icon on the far right to open the widget's settings tray.

  5. Configure the Global and Per-Language settings as described in the Features section above.

  6. Click "Update" and then "Save" the form display.

With the input configured, setting up the display is effortless.

  1. Navigate to the Manage display page for the same entity (e.g., Structure > Content types > Article > Manage display).
  2. Find your number field.
  3. In the "Format" column, select "Formatted as in input widget".
  4. Click the gear icon to configure it. You will see only one setting: "Source Form Mode". Select the form display (usually "Default") where you configured the widget.

    Click the gear icon to configure it. You will see only one setting: "Source Form Mode". This setting is the key to the formatter's simplicity and power. It tells the formatter from which form display it should inherit its entire configuration.

    Select the form display (usually "Default") where you previously configured the widget. By doing this, you are creating a direct link—telling the formatter to use the exact same set of language-aware symbols, separators, and rules that you defined for the input widget on that specific form.

    This ensures the display format is always perfectly synchronized with the input format and even allows for advanced use cases where different form modes (e.g., a "simplified entry" form) could have unique formatting, and you could choose which rule set the display should follow.

  5. Click "Update" and "Save".

That's it. There is no need to manually configure symbols, separators, or any other formatting options for the display again. The display formatter now directly mirrors all the settings from the input widget. If you ever need to change the number format (for instance, to update a currency symbol), you only need to change it in one place—the widget settings on the "Manage form display" page—and the display on the front end will automatically update to match.

Additional Requirements

This module requires the third-party AutoNumeric.js JavaScript library (v4.x) to function.

Per Drupal.org policy, which prohibits bundling third-party libraries directly within modules, you must download the library and place it in your site's libraries folder. The final path to the minified file should be: /libraries/autonumeric/autonumeric.min.js

You can download the library from the official AutoNumeric.js releases page on GitHub or from here https://cdn.jsdelivr.net/npm/[email protected]/dist/autoNumeric.min.js. 4.10.8 is the version that was current at publishing this module. So you may need to adapt the link to a newer version if available.
The autonumeric package contains more files than needed. For a production site you should delete all files but the autonumeric.min.js file.

For Composer-based sites, the recommended way to install the library is to run the following command from your project root:
composer require npm-asset/autonumeric

If that should not work for you: For detailed instructions, including the necessary one-time composer.json setup and the alternative manual installation method, please consult the README.md file included with the module.

Similar projects

If there are modules providing similar functionality, please describe what differentiates them.

Masked Input: Provides a generic input masking utility for text fields but is not specifically designed for numeric or currency formatting. Formatted Number Input is purpose-built for numbers and is aware of language-specific conventions like decimal separators and currency placement.
Field Formatter: A powerful suite of formatters. While you can configure some numeric formatting with it, it does not provide a corresponding input widget for a live, masked data entry experience. The key differentiator of this module is the tight integration between the widget (the form) and the formatter (the display).

Supporting this Module

This module is free and open source.
If you find it useful, consider documenting your own Drupal modules much better or provide documentation for things that cost you a lot of time figuring out to make modules work.

Module File Structure

This is the complete file structure for the module. Note that the third-party autonumeric.min.js library should not be included in the module's repository; it must be downloaded by the end-user per Drupal.org policy.

formatted_number_input/
├── config/
│   └── schema/
│   └── formatted_number_input.schema.yml
├── css/
│   └── formatted_number_input.css
├── js/
│   ├── lib/
│   │   └── autonumeric.min.js (Note: Not committed with the module)
│   └── formatted_number_input.js
├── src/
│   └── Plugin/
│   └── Field/
│   ├── FieldFormatter/
│   │   └── FormattedNumberAsWidgetFormatter.php
│   └── FieldWidget/
│   └── FormattedNumberWidget.php
├── tests/
│   └── src/
│   ├── Kernel/
│   │   └── FormattedNumberFieldTest.php
│   └── Unit/
│   └── UnformatValueTest.php
├── composer.json
├── formatted_number_input.info.yml
├── formatted_number_input.libraries.yml
└── formatted_number_input.module

Background and Design Decisions

This section provides extra detail for developers and site builders to better understand the module's internal logic and design choices.

How Decimal "Scale" is Handled

The module respects the native field configuration you've already set up in Drupal, ensuring data consistency from input all the way to the database. The number of digits behind the decimal separator is derived directly from the "Scale" setting of the Drupal number field itself.
The module was intentionally designed not to have its own setting for this. Instead, it reads the configuration of the field it is attached to, ensuring that the input format always matches the storage format.

  • Where to Find the Core Setting in Drupal: When you add a Decimal or Float field to a content type (or any entity), you configure its "Field Settings". In that form, you will find the "Scale" option, which defines how many digits are allowed after the decimal point.
  • Navigation Path: Structure > Content types > [Your Content Type] > Manage fields > Edit (for your number field).
  • The Code Responsible: The logic is in the formElement() method of the src/Plugin/Field/FieldWidget/FormattedNumberWidget.php file. Specifically, it's this line where the options for the JavaScript library are being assembled:
    'decimalPlaces' => $this->fieldDefinition->getType() === 'integer' ? 0 : ($field_settings['scale'] ?? 2),
    

Why the Decimal Character is Standardized to a Period

The module expects that PHP and the SQL database will always use a period (.) as the decimal character for data processing, regardless of what the user sees.

  • System Requirement: PHP's core functionality for converting strings to numbers (type casting) is locale-independent and only recognizes a period as a valid decimal separator. Drupal's Form and Database APIs are built on this foundation.
  • The Module's Role: This module acts as the bridge between the user-facing Presentation Layer and the system's Data/Logic Layer. It allows the user to input data in their localized format (e.g., with a comma decimal separator). The unformatValue() function then acts as a "standardizer." It takes the localized user input and converts it into the universal format (1.234,56 becomes 1234.56) that PHP and SQL expect before any further processing occurs.

Client-Side Value Loading

To ensure robustness and prevent mis-parsing of values, the module uses a specific three-step loading process:

  1. The server sends an empty <input> field to the browser. This prevents the AutoNumeric library from trying to parse an initial value that might be in the wrong format.
  2. The server also sends the raw, unformatted number (e.g., 12345.67) and the complete, language-aware configuration in separate data-* attributes on the input element.
  3. The JavaScript then initializes AutoNumeric on the empty field with the correct formatting rules and immediately calls the library's .set() method, passing it the raw number. The .set() method is designed to take a raw value and format it correctly according to the rules, resulting in a perfectly formatted number being displayed to the user.

Edge Case: Stale Form vs. Updated Configuration

The value loading process described above was specifically designed to solve a tricky edge case.

The Scenario: A user has two browser tabs open: Tab 1 shows the widget's configuration form (.../form-display) and Tab 2 shows a node edit page (.../edit) containing a field that uses the widget. The user changes the number format (e.g., from US to European separators) in Tab 1 and saves. They then go to Tab 2 and simply press the browser's reload button.
The Problem: Without the robust loading mechanism, the browser might reload the page with a stale, pre-formatted value (e.g., $1,234.56) while the JavaScript receives the new configuration rules (expecting €1.234,56). This can cause the library to fail parsing, often resulting in a blank field.
The Solution: By always sending an empty input field and passing the raw value in a data- attribute, we ensure the library never tries to parse a value using the wrong rules. It always starts fresh and applies the latest configuration to the raw, universal data.

Note: The development of this module was assisted by AI tools to help with code generation and documentation. All code and documentation generated with AI assistance were reviewed, tested, and modified by the project maintainer to the best of his knowledge and belief.

Activity

Total releases
4
First release
Jun 2025
Latest release
7 months ago
Release cadence
5 days
Stability
50% stable

Release Timeline

Releases

Version Type Release date
1.0.3 Stable Jul 8, 2025
1.0.2 Stable Jul 7, 2025
1.0.0-beta1 Pre-release Jun 23, 2025
1.0.x-dev Dev Jun 23, 2025