JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 3859
  • Score
    100M100P100Q123463F
  • License MIT

React masked input component and hooks

Package Exports

  • react-hook-mask
  • react-hook-mask/dist/cjs/index.js
  • react-hook-mask/dist/esm/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (react-hook-mask) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

React Masked Input and Hooks

npm downloads npm npm

Quickstart | Examples | Demo

Features

  • Support custom masks and mask rules to define which characters are allowed.
  • Can generate different masks based on the current value.
  • Preserve the cursor position when the value is changed, or when a new value (or part of it) is pasted, even when the mask changes.
  • Extensible, allowing the use of the generic hook by different components.
  • Default hook for web (DOM) components, as well as an implementation of the react-dom input component that uses the hook.
  • Function createDefaultMaskGenerator to easily create a mask generator that generates a single mask (independent of the value).

Install

npm install react-hook-mask

Quickstart

import React from 'react';
import { MaskedInput, createDefaultMaskGenerator } from 'react-hook-mask';

const maskGenerator = createDefaultMaskGenerator('999 999 9999');

const Quickstart = () => {
    const [value, setValue] = React.useState('');

    return (
        <div>
            <MaskedInput
                maskGenerator={maskGenerator}
                value={value}
                onChange={setValue}
            />
            <div>Value (no mask):</div>
            <div>{value}</div>
        </div>
    );
};

export default Quickstart;

You can define a boolean property keepMask with the value true to preserve the mask in the value provided (defined with setValue).

Define custom rules

Define a map custom rules for characters in the mask that must satisfy a regex provided. Characters in the mask not present in the rules are seen as static mask characters (as opposed to user provided characters), and will be included automatically in the display value.

import React from 'react';
import { MaskedInput } from 'react-hook-mask';

const MY_RULES = new Map([
    ['C', /[A-Za-z]/],
    ['N', /\d/],
]);

const createMaskGenerator = (mask) => ({
    rules: MY_RULES,
    generateMask: () => mask,
});

const maskGenerator = createMaskGenerator('CCC-NNNN');

const CustomRules = () => {
    const [value, setValue] = React.useState('');

    return (
        <div>
            <MaskedInput
                maskGenerator={maskGenerator}
                value={value}
                onChange={setValue}
            />
            <div>Value (no mask):</div>
            <div>{value}</div>
        </div>
    );
};

export default CustomRules;

Define a dynamic mask

A different mask can be defined based on the current mask value. The map DEFAULT_MASK_RULES can be used as the default rules, but custom rules can be defined too. A transform optional function can be used to transform the string if needed (in the example below, instead of blocking lowercase letters, they are converted to uppercase).

import React from 'react';
import { MaskedInput, DEFAULT_MASK_RULES } from 'react-hook-mask';

const maskGenerator = {
    rules: DEFAULT_MASK_RULES,
    generateMask: (value) =>
        (value?.replaceAll('-', '').length ?? 0) <= 10
            ? 'AAA-AAA-AAAA'
            : 'AAA-AAA-AAA-AAAA',
    transform: (v) => v?.toUpperCase(),
};

const DynamicMask = () => {
    const [value, setValue] = React.useState('');

    return (
        <div>
            <MaskedInput
                maskGenerator={maskGenerator}
                value={value}
                onChange={setValue}
            />
            <div>Value (no mask):</div>
            <div>{value}</div>
        </div>
    );
};

export default DynamicMask;

Custom DOM component

Use any mask in a custom DOM component (as long it behaves as an HTML input).

import React from 'react';
import { useWebMask } from 'react-hook-mask';
import MyInput from './my-input';

const CustomDOMComponent = React.forwardRef(
    (
        {
            maskGenerator,
            value: outerValue,
            onChange: onChangeOuter,
            keepMask,
            ...otherProps
        },
        outerRef,
    ) => {
        const { value, onChange, ref } = useWebMask({
            maskGenerator,
            value: outerValue,
            onChange: onChangeOuter,
            keepMask,
            ref: outerRef,
        });

        // The properties myValue, myOnChange and myRef are just examples
        return (
            <MyInput
                {...otherProps}
                myValue={value ?? ''}
                myOnChange={onChange}
                myRef={ref}
            />
        );
    },
);

export default CustomDOMComponent;

You can see the default MaskedInput component provided by this package as a reference.

Custom mask hook

Extend the hook to be used by a custom component (or several components, as long as the way to get and to change the cursor position is the same for those components).

The only requirement for the creation of a custom hook is that the input component must have a way to retrieve and to modify the cursor position (in the example below, the read-write property myPosition was used as an example).

import React from 'react';
import { useRefMask } from 'react-hook-mask';

export const useMyMask = ({
    maskGenerator,
    value,
    onChange,
    keepMask,
    ref: outerRef,
}) => {
    const getCursorPosition = React.useCallback((el) => {
        const cursorPosition = el?.myPosition ?? 0;
        return cursorPosition;
    }, []);

    const setCursorPosition = React.useCallback((cursorPosition, el) => {
        if (el) {
            el.myPosition = cursorPosition;
        }
    }, []);

    const { displayValue, setDisplayValue, ref } = useRefMask({
        value,
        maskGenerator,
        getCursorPosition,
        setCursorPosition,
        onChange,
        keepMask,
        ref: outerRef,
    });

    return { value: displayValue, onChange: setDisplayValue, ref };
};

The hook useRefMask wraps the generic useMask hook and was created to allow the use of the component ref even if an external ref is received without having to add boilerplate to handle this case.

You can see the useWebMask hook provided by this package as a reference.