React input component that accepts mask patterns for formatted text input
npx @tessl/cli install tessl/npm-react-text-mask@5.5.0React Text Mask is a React input component that provides text masking functionality, allowing developers to create formatted input fields for phone numbers, dates, currency, zip codes, and other structured data types. It offers a flexible mask API that supports both static patterns and dynamic functions, with real-time input formatting and full compatibility with standard HTML input props.
npm install react-text-maskimport MaskedInput from "react-text-mask";For the utility function:
import MaskedInput, { conformToMask } from "react-text-mask";CommonJS:
const MaskedInput = require("react-text-mask");
const { conformToMask } = require("react-text-mask");import React from "react";
import MaskedInput from "react-text-mask";
export default function PhoneForm() {
return (
<div>
<MaskedInput
mask={['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]}
className="form-control"
placeholder="Enter a phone number"
guide={false}
onBlur={() => {}}
onChange={() => {}}
/>
</div>
);
}Important: React Text Mask only supports input types: text, tel, url, password, and search. Other types like email or number are not supported due to browser API limitations.
React Text Mask is built around several key concepts:
The MaskedInput component has specific behavior during its lifecycle:
initTextMask()mask pattern changes (string comparison: mask.toString() !== prevProps.mask.toString())pipe function changes (function string comparison for functions, null/undefined state changes)guide, placeholderChar, showMask (shallow object comparison)value differs from actual input element value (value !== this.inputElement.value)isValueChanged || isSettingChanged)Main React component that wraps input elements with text masking functionality.
/**
* React component for masked input functionality
* Extends React.PureComponent with text masking capabilities
*/
class MaskedInput extends React.PureComponent {
constructor(props: MaskedInputProps);
/** Internal methods (advanced usage) */
setRef(inputElement: HTMLInputElement): void;
initTextMask(): void;
onChange(event: Event): void;
onBlur(event: Event): void;
}
interface MaskedInputProps {
/** Mask pattern definition (required) */
mask: MaskPattern | MaskFunction | boolean | MaskObject;
/** Shows placeholder characters when true (default: true) */
guide?: boolean;
/** Controlled input value */
value?: string | number;
/** Post-processing function for conformed values */
pipe?: PipeFunction;
/** Character for fillable spots (default: '_') */
placeholderChar?: string;
/** Prevents character position changes (default: false) */
keepCharPositions?: boolean;
/** Shows mask as placeholder when input empty (default: false) */
showMask?: boolean;
/** Custom render prop for input element (default: renders standard <input>) */
render?: RenderFunction;
/** Standard HTML input event handlers */
onBlur?: (event: Event) => void;
onChange?: (event: Event) => void;
/** All other standard HTML input props are supported */
[key: string]: any;
}
type MaskPattern = (string | RegExp)[];
type MaskFunction = (rawValue: string, config: MaskConfig) => MaskPattern | false;
interface MaskObject {
mask: MaskPattern | MaskFunction;
pipe: PipeFunction;
}
interface MaskConfig {
currentCaretPosition: number;
previousConformedValue: string;
placeholderChar: string;
}
type PipeFunction = (
conformedValue: string,
config: PipeConfig
) => false | string | PipeResult;
interface PipeConfig extends MaskConfig {
rawValue: string;
guide: boolean;
placeholderChar: string;
pipe: PipeFunction;
placeholder: string;
keepCharPositions: boolean;
}
interface PipeResult {
value: string;
indexesOfPipedChars: number[];
}
type RenderFunction = (
ref: (element: HTMLInputElement) => void,
props: InputProps
) => React.ReactElement;
interface InputProps {
onBlur: (event: Event) => void;
onChange: (event: Event) => void;
defaultValue: string | number;
[key: string]: any;
}
/** Default render function when none provided */
const defaultRender: RenderFunction = (ref, props) => <input ref={ref} {...props} />;Usage Examples:
import React from "react";
import MaskedInput from "react-text-mask";
// Basic phone number mask
<MaskedInput
mask={['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]}
placeholder="Enter phone number"
/>
// Currency mask with pipe function
<MaskedInput
mask={[/\d/, /\d/, /\d/, /\d/, /\d/, /\d/, /\d/]}
pipe={(conformedValue) => {
const numericValue = conformedValue.replace(/\D/g, '');
return '$' + numericValue;
}}
/>
// Dynamic mask using function
<MaskedInput
mask={(rawValue) => {
if (rawValue.startsWith('1')) {
// US phone format
return ['1', ' ', '(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];
} else {
// Regular phone format
return ['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];
}
}}
/>
// Custom render with styled-components
<MaskedInput
mask={['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]}
render={(ref, props) => (
<MyStyledInput innerRef={ref} {...props} />
)}
/>
// Disabled masking
<MaskedInput mask={false} />Mask patterns define how user input will be formatted and can be static arrays or dynamic functions.
/**
* Static mask pattern using array of strings and regular expressions
* - Strings represent literal characters that appear in the formatted output
* - RegExp patterns define validation rules for user input at that position
*/
type MaskPattern = (string | RegExp)[];Examples:
// Phone number: (555) 123-4567
const phoneMask = ['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];
// Date: MM/DD/YYYY
const dateMask = [/[01]/, /\d/, '/', /[0-3]/, /\d/, '/', /[12]/, /\d/, /\d/, /\d/];
// ZIP code: 12345 or 12345-6789
const zipMask = [/\d/, /\d/, /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];/**
* Dynamic mask function for variable-length or conditional formatting
* @param rawValue - Current unformatted input value
* @param config - Configuration object with caret position and previous value
* @returns Mask pattern array or false to disable masking
*/
type MaskFunction = (rawValue: string, config: MaskConfig) => MaskPattern | false;
interface MaskConfig {
currentCaretPosition: number;
previousConformedValue: string;
placeholderChar: string;
}Usage Example:
// Email-like mask that grows with input
const emailMask = (rawValue) => {
const atIndex = rawValue.indexOf('@');
if (atIndex === -1) {
// Before @ symbol
return Array(rawValue.length).fill(/[a-zA-Z0-9]/);
} else {
// After @ symbol, add domain pattern
const beforeAt = Array(atIndex).fill(/[a-zA-Z0-9]/);
const afterAt = ['@'].concat(Array(rawValue.length - atIndex - 1).fill(/[a-zA-Z0-9.]/));
return beforeAt.concat(afterAt);
}
};Post-processing functions that modify the conformed value before display.
/**
* Pipe function for post-processing conformed values
* @param conformedValue - Value after mask has been applied
* @param config - Configuration object with input context
* @returns false to reject, string for simple modification, or object for complex changes
*/
type PipeFunction = (
conformedValue: string,
config: PipeConfig
) => false | string | PipeResult;
interface PipeConfig extends MaskConfig {
rawValue: string;
guide: boolean;
placeholderChar: string;
pipe: PipeFunction;
placeholder: string;
keepCharPositions: boolean;
}
interface PipeResult {
/** The modified value */
value: string;
/** Indexes of characters added by the pipe function */
indexesOfPipedChars: number[];
}Usage Examples:
// Simple uppercase transformation
const uppercasePipe = (conformedValue) => {
return conformedValue.toUpperCase();
};
// Currency formatting with dollar sign
const currencyPipe = (conformedValue) => {
const numericValue = conformedValue.replace(/\D/g, '');
if (!numericValue) return '';
return {
value: '$' + numericValue,
indexesOfPipedChars: [0] // Dollar sign added at index 0
};
};
// Validation pipe that rejects invalid input
const validationPipe = (conformedValue) => {
if (conformedValue.includes('000')) {
return false; // Reject values containing '000'
}
return conformedValue;
};Standalone utility function for applying masks to text without React components.
/**
* Utility function to transform text according to mask pattern
* @param text - Input text to conform
* @param mask - Mask pattern array
* @param config - Optional configuration object
* @returns Object with conformed value and metadata
*/
function conformToMask(
text: string,
mask: MaskPattern,
config?: ConformConfig
): ConformResult;
interface ConformConfig {
/** Guide mode setting (default: true) */
guide?: boolean;
/** Previous conformed value for comparison */
previousConformedValue?: string;
/** Placeholder character (default: '_') */
placeholderChar?: string;
/** Full placeholder string */
placeholder?: string;
/** Current cursor position */
currentCaretPosition?: number;
/** Keep character positions setting */
keepCharPositions?: boolean;
}
interface ConformResult {
/** The text after applying mask */
conformedValue: string;
/** Metadata about the operation */
meta: {
/** Whether any input characters were rejected */
someCharsRejected: boolean;
};
}Usage Examples:
import { conformToMask } from "react-text-mask";
// Basic usage
const phoneNumber = '5551234444';
const phoneMask = ['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];
const result = conformToMask(phoneNumber, phoneMask, { guide: false });
console.log(result.conformedValue); // "(555) 123-4444"
console.log(result.meta.someCharsRejected); // false
// With configuration
const partialResult = conformToMask('555', phoneMask, {
guide: true,
placeholderChar: '*'
});
console.log(partialResult.conformedValue); // "(555) ***-****"React Text Mask supports the following HTML input types:
text (default and recommended)telurlpasswordsearchNote: Other input types like email or number are not supported due to browser API limitations. Use type="text" with appropriate masks for these scenarios.
// US phone number: (555) 123-4567
const usMask = ['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];
// International format: +1 (555) 123-4567
const internationalMask = ['+', /\d/, ' ', '(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];// MM/DD/YYYY
const dateMask = [/[01]/, /\d/, '/', /[0-3]/, /\d/, '/', /[12]/, /\d/, /\d/, /\d/];
// DD-MM-YYYY
const europeanDateMask = [/[0-3]/, /\d/, '-', /[01]/, /\d/, '-', /[12]/, /\d/, /\d/, /\d/];// 4-4-4-4 format
const creditCardMask = [
/\d/, /\d/, /\d/, /\d/, '-',
/\d/, /\d/, /\d/, /\d/, '-',
/\d/, /\d/, /\d/, /\d/, '-',
/\d/, /\d/, /\d/, /\d/
];// XXX-XX-XXXX
const ssnMask = [/\d/, /\d/, /\d/, '-', /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];