CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-number-format

React component library for formatting numbers in input fields and text display with sophisticated caret engine and customizable patterns.

Pending
Overview
Eval results
Files

base-component.mddocs/

Base Component System

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.

Capabilities

NumberFormatBase Component

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)}
    />
  );
}

Display Type Options

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>
  )}
/>

Custom Input Components

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}
/>

Value Change Handling

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('$', '')}
    />
  );
}

Validation and Filtering

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>
  );
}

Caret Positioning Control

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}
/>

Character Comparison Logic

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

docs

base-component.md

index.md

numeric-formatting.md

pattern-formatting.md

react-hooks.md

utility-functions.md

tile.json