React component library for formatting numbers in input fields and text display with sophisticated caret engine and customizable patterns.
—
Core component providing customizable formatting functionality that both NumericFormat and PatternFormat extend. Use NumberFormatBase when you need complete control over formatting logic or want to create custom formatting behaviors.
The foundational component that provides the core formatting infrastructure with customizable format and removeFormatting functions.
/**
* Base component providing core formatting functionality
* @param props - Configuration options for base formatting behavior
* @returns React element with customizable formatting logic
*/
function NumberFormatBase<BaseType = InputAttributes>(
props: NumberFormatBaseProps<BaseType>
): React.ReactElement;
interface NumberFormatBaseProps<BaseType = InputAttributes> {
/** Input type attribute */
type?: 'text' | 'tel' | 'password';
/** Whether to render as input or text display */
displayType?: 'input' | 'text';
/** Input mode for mobile keyboards */
inputMode?: InputAttributes['inputMode'];
/** Custom component to render instead of default input */
customInput?: React.ComponentType<BaseType>;
/** Custom render function for text display mode */
renderText?: (formattedValue: string, otherProps: Partial<NumberFormatBaseProps>) => React.ReactNode;
/** Function to format input values for display */
format?: (inputValue: string) => string;
/** Function to remove formatting and extract raw value */
removeFormatting?: (inputValue: string, changeMeta?: ChangeMeta) => string;
/** Ref callback or ref object for the input element */
getInputRef?: ((el: HTMLInputElement) => void) | React.Ref<any>;
/** Current value of the input */
value?: number | string | null;
/** Default value for uncontrolled usage */
defaultValue?: number | string | null;
/** Whether the value prop should be treated as numeric string */
valueIsNumericString?: boolean;
/** Callback when value changes with formatted and raw values */
onValueChange?: OnValueChange;
/** Function to validate if new values should be allowed */
isAllowed?: (values: NumberFormatValues) => boolean;
/** Function to determine valid caret positions */
getCaretBoundary?: (formattedValue: string) => boolean[];
/** Function to validate individual input characters */
isValidInputCharacter?: (character: string) => boolean;
/** Function to determine if characters at different positions represent the same logical character */
isCharacterSame?: IsCharacterSame;
/** Standard input event handlers */
onKeyDown?: InputAttributes['onKeyDown'];
onMouseUp?: InputAttributes['onMouseUp'];
onChange?: InputAttributes['onChange'];
onFocus?: InputAttributes['onFocus'];
onBlur?: InputAttributes['onBlur'];
}Usage Examples:
import React from "react";
import { NumberFormatBase } from "react-number-format";
// Custom hex color input
function HexColorInput({ value, onChange }) {
const formatHex = (inputValue: string) => {
const hex = inputValue.replace(/[^0-9A-Fa-f]/g, '').slice(0, 6);
return `#${hex.toUpperCase()}`;
};
const removeHexFormatting = (inputValue: string) => {
return inputValue.replace('#', '').replace(/[^0-9A-Fa-f]/g, '');
};
const validateHex = (character: string) => {
return /[0-9A-Fa-f]/.test(character);
};
return (
<NumberFormatBase
value={value}
format={formatHex}
removeFormatting={removeHexFormatting}
isValidInputCharacter={validateHex}
onValueChange={(values) => onChange(values.value)}
placeholder="#000000"
maxLength={7}
/>
);
}
// Custom uppercase text input
function UppercaseInput({ value, onChange }) {
return (
<NumberFormatBase
value={value}
format={(inputValue) => inputValue.toUpperCase()}
removeFormatting={(inputValue) => inputValue.toUpperCase()}
onValueChange={(values) => onChange(values.value)}
isAllowed={(values) => {
// Only allow alphabetic characters
return /^[A-Z]*$/.test(values.value);
}}
/>
);
}
// Custom input with Material-UI integration
function MaterialNumberInput({ value, onChange, ...props }) {
return (
<NumberFormatBase
{...props}
value={value}
onValueChange={(values) => onChange(values.floatValue)}
customInput={TextField} // Material-UI TextField
format={(value) => value} // No formatting
removeFormatting={(value) => value.replace(/[^0-9.-]/g, '')}
isValidInputCharacter={(char) => /[0-9.-]/.test(char)}
/>
);
}NumberFormatBase supports both input and text display modes:
// Input mode (default) - renders interactive input
<NumberFormatBase
displayType="input"
value="123.45"
format={(value) => `$${value}`}
/>
// Text mode - renders formatted text
<NumberFormatBase
displayType="text"
value="123.45"
format={(value) => `$${value}`}
renderText={(formattedValue, props) => (
<span className="currency" {...props}>
{formattedValue}
</span>
)}
/>Integrate with UI libraries and custom components:
import { TextField } from '@mui/material';
import { Input } from 'antd';
// Material-UI integration
<NumberFormatBase
customInput={TextField}
format={formatFunction}
removeFormatting={removeFunction}
// TextField props
label="Amount"
variant="outlined"
size="small"
/>
// Ant Design integration
<NumberFormatBase
customInput={Input}
format={formatFunction}
removeFormatting={removeFunction}
// Input props
size="large"
prefix={<DollarOutlined />}
/>
// Custom styled component
const StyledInput = (props) => (
<input {...props} className="custom-formatted-input" />
);
<NumberFormatBase
customInput={StyledInput}
format={formatFunction}
removeFormatting={removeFunction}
/>The onValueChange callback provides comprehensive information about value changes:
type OnValueChange = (values: NumberFormatValues, sourceInfo: SourceInfo) => void;
interface NumberFormatValues {
/** Parsed numeric value (undefined if not a valid number) */
floatValue: number | undefined;
/** Formatted display value */
formattedValue: string;
/** Raw input value without formatting */
value: string;
}
interface SourceInfo {
/** The DOM event that triggered the change (if applicable) */
event?: React.SyntheticEvent<HTMLInputElement>;
/** Whether change came from user input or props update */
source: 'event' | 'prop';
}Usage Examples:
function AdvancedInput({ onChange, onValidation }) {
const handleValueChange = (values, sourceInfo) => {
const { floatValue, formattedValue, value } = values;
const { event, source } = sourceInfo;
// Handle different value representations
onChange({
numeric: floatValue,
formatted: formattedValue,
raw: value
});
// Provide validation feedback
const isValid = floatValue !== undefined && floatValue > 0;
onValidation(isValid);
// Log changes from user input
if (source === 'event') {
console.log('User entered:', value);
}
};
return (
<NumberFormatBase
onValueChange={handleValueChange}
format={(value) => `$${value}`}
removeFormatting={(value) => value.replace('$', '')}
/>
);
}Control what input is allowed with validation functions:
// Restrict to positive numbers only
<NumberFormatBase
isAllowed={(values) => {
const { floatValue } = values;
return floatValue === undefined || floatValue >= 0;
}}
format={(value) => value}
removeFormatting={(value) => value}
/>
// Limit character input
<NumberFormatBase
isValidInputCharacter={(char) => /[0-9.]/.test(char)}
format={(value) => value}
removeFormatting={(value) => value}
/>
// Complex validation with error handling
function ValidatedInput({ max = 1000 }) {
const [error, setError] = useState('');
return (
<div>
<NumberFormatBase
isAllowed={(values) => {
const { floatValue } = values;
if (floatValue === undefined) return true;
if (floatValue > max) {
setError(`Value cannot exceed ${max}`);
return false;
}
setError('');
return true;
}}
format={(value) => value}
removeFormatting={(value) => value}
/>
{error && <div className="error">{error}</div>}
</div>
);
}Control cursor behavior with caret boundary functions:
/**
* Function to determine valid caret positions
* @param formattedValue - The current formatted display value
* @returns Array of booleans where true indicates valid caret position
*/
type GetCaretBoundary = (formattedValue: string) => boolean[];Usage Examples:
// Only allow cursor in numeric positions of "$ 123.45"
function CurrencyCaretBoundary(formattedValue: string): boolean[] {
return formattedValue.split('').map((char, index) => {
// Allow cursor after $ and space, and at numeric positions
return index >= 2 || /[0-9.]/.test(char);
});
}
<NumberFormatBase
format={(value) => `$ ${value}`}
removeFormatting={(value) => value.replace(/[$ ]/g, '')}
getCaretBoundary={CurrencyCaretBoundary}
/>Define how characters are compared during formatting:
/**
* Function to determine if characters represent the same logical value
*/
type IsCharacterSame = (compareProps: {
currentValue: string;
lastValue: string;
formattedValue: string;
currentValueIndex: number;
formattedValueIndex: number;
}) => boolean;This is useful for advanced scenarios where logical characters might be represented differently in formatted vs unformatted states.
Install with Tessl CLI
npx tessl i tessl/npm-react-number-format