react-input

repository·main·Indexed 41 days ago

https://github.com/goncharukorg/react-input

A collection of React packages for enhancing input elements with masking and locale-specific number, currency, and percentage formatting. Includes @react-input/mask for applying input masks via the InputMask component or useMask hook, and @react-input/number-format for localized formatting, all integrated through @react-input/core.

Tokens
14.8K
Snippets
50
Records
61
Agent score
44%

What's inside react-input

  1. Overview of react-input packages

    main

    The react-input ecosystem provides specialized tools for managing input behavior in React applications. It is divided into three main packages:

    • @react-input/core: The base package used for service-level logic and as a dependency for other packages in the @react-input scope.
    • @react-input/mask: Provides functionality to apply input masks to an input element using either a dedicated component or a hook.
    • @react-input/number-format: Provides functionality to apply locale-specific formatting for numbers, currencies, and percentages using either a dedicated component or a hook.
  2. Understand the role of @react-input/core

    main

    @react-input/core is a service package that facilitates the use of other specialized packages within the @react-input ecosystem. It acts as a central point for integrating specialized input behaviors like masking and number formatting into your React applications.

    The core package enables the use of:

    • @react-input/mask: For applying input masks via components or hooks.
    • @react-input/number-format: For applying locale-specific number, currency, and percentage formatting via components or hooks.
  3. How @react-input/mask works

    main

    The library allows you to apply input masks to input elements using two primary methods: a pre-built InputMask component or a useMask hook.

    • InputMask component: A standard input element with built-in masking logic. It is ideal for standard use cases and supports integration with custom components via the component prop.
    • useMask hook: A hook that returns a ref which must be attached to a standard HTML input element. This is useful when you want to use your own existing input components or elements.

    A key design principle is that the library only relies on user-supplied characters, meaning you can safely include any character in the mask without unexpected behavior.

    // Using the component
    <InputMask mask="+0 (___) ___-__-__" replacement={{ _: /\d/ }} />
    
    // Using the hook
    const inputRef = useMask({
      mask: '+0 (___) ___-__-__',
      replacement: { _: /\d/ },
    });
    <input ref={inputRef} />
  4. Important changes in newer versions regarding events

    main

    In newer versions of @react-input/number-format, the custom input-number-format event and the onNumberFormat method have been removed.

    Instead, the library focuses on using standard React events and methods like onChange. This change was made to ensure predictable event firing order and better coordination with React's event system.

    If you need to access the data previously provided by the detail property of the input-number-format event, you should use the provided Utils instead.

  5. Use @react-input/number-format via CDN

    main

    When using the library via CDN, you access a global ReactInput.NumberFormat class.

    1. Instantiate the class with your formatting options.
    2. Use the .register(element) method to apply formatting to specific DOM elements.
    3. Use the .unregister(element) method to remove formatting from an element.

    You can register multiple elements to a single NumberFormat instance.

    const numberFormat = new ReactInput.NumberFormat({
      locales: 'en',
      maximumFractionDigits: 2,
    });
    
    const elements = document.getElementsByName('amount');
    
    elements.forEach((element) => {
      numberFormat.register(element);
    });
    
    // To disable formatting:
    // elements.forEach((element) => {
    //   numberFormat.unregister(element);
    // });
  6. Integrate `@react-input/mask` with Material UI

    main

    There are two ways to integrate with Material UI (MUI) components like TextField:

    Option 1: Using inputComponent

    Create a component wrapped in forwardRef that returns an InputMask. Pass this to the inputComponent property of the MUI InputProps.

    Option 2: Using the useMask hook

    Use the useMask hook to generate a ref and pass it directly to the inputRef property of the MUI component. This is often the cleaner approach for hook-based integration.

    // Option 1: inputComponent
    import { forwardRef } from 'react';
    import { InputMask, type InputMaskProps } from '@react-input/mask';
    import { TextField } from '@mui/material';
    
    const ForwardedInputMask = forwardRef<HTMLInputElement, InputMaskProps>((props, forwardedRef) => {
      return <InputMask ref={forwardedRef} mask="___-___" replacement="_" {...props} />;
    });
    
    export default function App() {
      return (
        <TextField
          InputProps={{ inputComponent: ForwardedInputMask }}
        />
      );
    }
    
    // Option 2: useMask hook
    import { useMask } from '@react-input/mask';
    import { TextField } from '@mui/material';
    
    export default function App() {
      const inputRef = useMask({ mask: '___-___', replacement: '_' });
    
      return <TextField inputRef={inputRef} />;
    }
  7. Use TypeScript with InputNumberFormat

    main

    The @react-input/number-format package provides full TypeScript support. You can import types directly from @react-input/number-format or @react-input/number-format/types.

    Property Type Support

    InputNumberFormat adapts its props based on whether you are using it as a standard input or as a Higher-Order Component (HOC) via the component prop:

    1. Standard Input: By default, it behaves like an input element and supports all React.InputHTMLAttributes<HTMLInputElement>.
    2. Custom Component: If you pass a component prop, it merges NumberFormatOptions with the props of your integrated component.

    Fixing Type Inference for Rest Parameters

    If you are passing ...rest props (e.g., from a component with any types), TypeScript might fail to correctly infer the types for the component and its properties. To fix this, pass your component's type explicitly to the InputNumberFormat generic.

    import { InputNumberFormat } from '@react-input/number-format';
    import { CustomInput } from './CustomInput';
    
    export default function Component(props: any) {
      // Pass the component type explicitly to fix inference issues
      return <InputNumberFormat<typeof CustomInput> component={CustomInput} {...props} />;
    }
  8. Configure character replacement in masks

    main

    The replacement property maps characters in your mask string to Regular Expressions. When a user types, the input character is checked against the RegExp associated with that mask character.

    • Object mapping: Use an object where keys are the mask characters and values are RegExps (e.g., { d: /\d/ } for digits).
    • String shortcut: Passing a string like replacement="_" is equivalent to replacement={{ _: /./ }} (allows any character).

    Warning: Do not use actual digits as keys in the replacement object (e.g., { 9: /\d/ }). Keys are ignored during typing, which would prevent the user from entering that specific character.

    import { InputMask } from '@react-input/mask';
    
    export default function App() {
      // Maps 'd', 'm', and 'y' to digit regexps
      return <InputMask mask="dd.mm.yyyy" replacement={{ d: /\d/, m: /\d/, y: /\d/ }} showMask separate />;
    }
  9. Use @react-input/number-format in React

    main

    The @react-input/number-format package offers two primary ways to implement number formatting in React applications:

    1. InputNumberFormat Component: A standard input element enhanced with formatting logic. This is the preferred method if you want to use the component as a Higher-Order Component (HOC) to integrate with custom components or if you want additional capabilities.
    2. useNumberFormat Hook: A hook that returns a ref which must be attached to a standard input element. This is ideal for when you want to maintain full control over the underlying DOM element.

    Both methods use the Intl.NumberFormat constructor for localization. For consistent behavior, ensure the type property of the input is set to "text" (the default). Using other types will disable formatting and trigger a console warning.

    import { InputNumberFormat } from '@react-input/number-format';
    
    // Using the Component
    export default function App() {
      return <InputNumberFormat locales="en" maximumFractionDigits={2} />;
    }
    
    // Using the Hook
    import { useNumberFormat } from '@react-input/number-format';
    
    export default function App() {
      const inputRef = useNumberFormat({
        locales: 'en',
        maximumFractionDigits: 2,
      });
    
      return <input ref={inputRef} />;
    }
  10. Handle controlled inputs with @react-input/number-format

    main

    To support controlled inputs, @react-input/number-format does not modify the value passed to the input element. This means the state value must exactly match the formatted value displayed in the input.

    If your state contains unformatted numbers, use the format utility to convert the value into the correct formatted string before passing it to the value prop. Failure to do so will result in a console warning.

    For uncontrolled inputs, the library handles formatting automatically upon initialization.

    import { useState } from 'react';
    import { useNumberFormat, format } from '@react-input/number-format';
    
    const options = {
      locales: 'en',
      maximumFractionDigits: 2,
    };
    
    export default function App() {
      const inputRef = useNumberFormat(options);
      // Use format() to ensure the initial state matches the expected formatted string
      const defaultValue = format(123456789, options);
    
      const [value, setValue] = useState(defaultValue); 
    
      return <input ref={inputRef} value={value} onChange={(event) => setValue(event.target.value)} />;
    }
  11. Migrate from v1 to v2

    main

    When upgrading @react-input/number-format from version 1 to version 2, note the following breaking changes:

    Removal of onNumberFormat and input-number-format event

    To ensure better coordination with React's event system, the onNumberFormat method and the input-number-format event have been removed. You should now use the standard React onChange event.

    Accessing numeric values

    Instead of accessing data via the detail property of an onNumberFormat event, use the provided utility functions (like unformat) inside a standard onChange handler to extract the numeric value.

    // OLD (v1)
    <InputNumberFormat
      locales={locales}
      onNumberFormat={(event) => {
        const { value, number } = event.detail;
      }}
    />
    
    // NEW (v2)
    import { InputNumberFormat, unformat } from '@react-input/number-format';
    
    <InputNumberFormat
      locales={locales}
      onChange={(event) => {
        const value = event.target.value;
        const number = Number(unformat(value, locales));
      }}
    />