DEV Community

Riccardo Gregori
Riccardo Gregori

Posted on

React Numeric Input Control

I spent 2 days trying to make it work. I put it here for future reference.

import * as React from 'react';
import { Input } from "@fluentui/react-components";
import { useState } from "react";

export interface INumericInputProps {
    minimumFractionDigits?: number,
    maximumFractionDigits?: number,
    placeholder?: string,
    disabled?: boolean,
    value?: number,
    onChange: (value?: number) => void
}



const NumericInput : React.FC<INumericInputProps> = (props) => {
    const locale = "it-IT";
    const [textValue, setTextValue] = useState(props.value?.toLocaleString(locale) || "");

    const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
        const allowedKeys = [
            'ArrowUp', 
            'ArrowDown', 
            'ArrowLeft', 
            'ArrowRight', 
            'Tab', 
            'Shift', 
            'Control', 
            'Home', 
            'End', 
            'Backspace', 
            'Delete', 
            'Enter', 
            'Escape', 
            'Canc'
        ];
        if (!/[0-9,]/.test(event.key) && !allowedKeys.includes(event.key)) {
            event.preventDefault();
        }
    };


    const ontTextChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setTextValue(event.target.value);
    }

    const onTextBlur = () => {
        const cleanedText = textValue.replace(/\./g, '').replace(",", ".");
        const value = Number(cleanedText);

        let formattedValue = new Intl.NumberFormat('it-IT', {
            minimumFractionDigits: props.minimumFractionDigits || 0,
            maximumFractionDigits: props.maximumFractionDigits || 0,
        }).format(value);

        if (formattedValue === "NaN") {
            formattedValue = "";
        }

        setTextValue(formattedValue);

        if (formattedValue !== "") {
            props.onChange(value);
        }
    }


    return <Input
            type="text"
            appearance="filled-darker"
            placeholder={props.placeholder}
            disabled={props.disabled ?? false}
            onKeyDown={onKeyDown}
            onChange={ontTextChange}
            onBlur={onTextBlur}
            value={textValue}/>;
};

export default NumericInput;
Enter fullscreen mode Exit fullscreen mode

Planned improvement: localization. As of now supports only Italian locale.

Top comments (0)