0
# Base Component System
1
2
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.
3
4
## Capabilities
5
6
### NumberFormatBase Component
7
8
The foundational component that provides the core formatting infrastructure with customizable format and removeFormatting functions.
9
10
```typescript { .api }
11
/**
12
* Base component providing core formatting functionality
13
* @param props - Configuration options for base formatting behavior
14
* @returns React element with customizable formatting logic
15
*/
16
function NumberFormatBase<BaseType = InputAttributes>(
17
props: NumberFormatBaseProps<BaseType>
18
): React.ReactElement;
19
20
interface NumberFormatBaseProps<BaseType = InputAttributes> {
21
/** Input type attribute */
22
type?: 'text' | 'tel' | 'password';
23
/** Whether to render as input or text display */
24
displayType?: 'input' | 'text';
25
/** Input mode for mobile keyboards */
26
inputMode?: InputAttributes['inputMode'];
27
/** Custom component to render instead of default input */
28
customInput?: React.ComponentType<BaseType>;
29
/** Custom render function for text display mode */
30
renderText?: (formattedValue: string, otherProps: Partial<NumberFormatBaseProps>) => React.ReactNode;
31
/** Function to format input values for display */
32
format?: (inputValue: string) => string;
33
/** Function to remove formatting and extract raw value */
34
removeFormatting?: (inputValue: string, changeMeta?: ChangeMeta) => string;
35
/** Ref callback or ref object for the input element */
36
getInputRef?: ((el: HTMLInputElement) => void) | React.Ref<any>;
37
/** Current value of the input */
38
value?: number | string | null;
39
/** Default value for uncontrolled usage */
40
defaultValue?: number | string | null;
41
/** Whether the value prop should be treated as numeric string */
42
valueIsNumericString?: boolean;
43
/** Callback when value changes with formatted and raw values */
44
onValueChange?: OnValueChange;
45
/** Function to validate if new values should be allowed */
46
isAllowed?: (values: NumberFormatValues) => boolean;
47
/** Function to determine valid caret positions */
48
getCaretBoundary?: (formattedValue: string) => boolean[];
49
/** Function to validate individual input characters */
50
isValidInputCharacter?: (character: string) => boolean;
51
/** Function to determine if characters at different positions represent the same logical character */
52
isCharacterSame?: IsCharacterSame;
53
/** Standard input event handlers */
54
onKeyDown?: InputAttributes['onKeyDown'];
55
onMouseUp?: InputAttributes['onMouseUp'];
56
onChange?: InputAttributes['onChange'];
57
onFocus?: InputAttributes['onFocus'];
58
onBlur?: InputAttributes['onBlur'];
59
}
60
```
61
62
**Usage Examples:**
63
64
```typescript
65
import React from "react";
66
import { NumberFormatBase } from "react-number-format";
67
68
// Custom hex color input
69
function HexColorInput({ value, onChange }) {
70
const formatHex = (inputValue: string) => {
71
const hex = inputValue.replace(/[^0-9A-Fa-f]/g, '').slice(0, 6);
72
return `#${hex.toUpperCase()}`;
73
};
74
75
const removeHexFormatting = (inputValue: string) => {
76
return inputValue.replace('#', '').replace(/[^0-9A-Fa-f]/g, '');
77
};
78
79
const validateHex = (character: string) => {
80
return /[0-9A-Fa-f]/.test(character);
81
};
82
83
return (
84
<NumberFormatBase
85
value={value}
86
format={formatHex}
87
removeFormatting={removeHexFormatting}
88
isValidInputCharacter={validateHex}
89
onValueChange={(values) => onChange(values.value)}
90
placeholder="#000000"
91
maxLength={7}
92
/>
93
);
94
}
95
96
// Custom uppercase text input
97
function UppercaseInput({ value, onChange }) {
98
return (
99
<NumberFormatBase
100
value={value}
101
format={(inputValue) => inputValue.toUpperCase()}
102
removeFormatting={(inputValue) => inputValue.toUpperCase()}
103
onValueChange={(values) => onChange(values.value)}
104
isAllowed={(values) => {
105
// Only allow alphabetic characters
106
return /^[A-Z]*$/.test(values.value);
107
}}
108
/>
109
);
110
}
111
112
// Custom input with Material-UI integration
113
function MaterialNumberInput({ value, onChange, ...props }) {
114
return (
115
<NumberFormatBase
116
{...props}
117
value={value}
118
onValueChange={(values) => onChange(values.floatValue)}
119
customInput={TextField} // Material-UI TextField
120
format={(value) => value} // No formatting
121
removeFormatting={(value) => value.replace(/[^0-9.-]/g, '')}
122
isValidInputCharacter={(char) => /[0-9.-]/.test(char)}
123
/>
124
);
125
}
126
```
127
128
### Display Type Options
129
130
NumberFormatBase supports both input and text display modes:
131
132
```typescript
133
// Input mode (default) - renders interactive input
134
<NumberFormatBase
135
displayType="input"
136
value="123.45"
137
format={(value) => `$${value}`}
138
/>
139
140
// Text mode - renders formatted text
141
<NumberFormatBase
142
displayType="text"
143
value="123.45"
144
format={(value) => `$${value}`}
145
renderText={(formattedValue, props) => (
146
<span className="currency" {...props}>
147
{formattedValue}
148
</span>
149
)}
150
/>
151
```
152
153
### Custom Input Components
154
155
Integrate with UI libraries and custom components:
156
157
```typescript
158
import { TextField } from '@mui/material';
159
import { Input } from 'antd';
160
161
// Material-UI integration
162
<NumberFormatBase
163
customInput={TextField}
164
format={formatFunction}
165
removeFormatting={removeFunction}
166
// TextField props
167
label="Amount"
168
variant="outlined"
169
size="small"
170
/>
171
172
// Ant Design integration
173
<NumberFormatBase
174
customInput={Input}
175
format={formatFunction}
176
removeFormatting={removeFunction}
177
// Input props
178
size="large"
179
prefix={<DollarOutlined />}
180
/>
181
182
// Custom styled component
183
const StyledInput = (props) => (
184
<input {...props} className="custom-formatted-input" />
185
);
186
187
<NumberFormatBase
188
customInput={StyledInput}
189
format={formatFunction}
190
removeFormatting={removeFunction}
191
/>
192
```
193
194
### Value Change Handling
195
196
The onValueChange callback provides comprehensive information about value changes:
197
198
```typescript { .api }
199
type OnValueChange = (values: NumberFormatValues, sourceInfo: SourceInfo) => void;
200
201
interface NumberFormatValues {
202
/** Parsed numeric value (undefined if not a valid number) */
203
floatValue: number | undefined;
204
/** Formatted display value */
205
formattedValue: string;
206
/** Raw input value without formatting */
207
value: string;
208
}
209
210
interface SourceInfo {
211
/** The DOM event that triggered the change (if applicable) */
212
event?: React.SyntheticEvent<HTMLInputElement>;
213
/** Whether change came from user input or props update */
214
source: 'event' | 'prop';
215
}
216
```
217
218
**Usage Examples:**
219
220
```typescript
221
function AdvancedInput({ onChange, onValidation }) {
222
const handleValueChange = (values, sourceInfo) => {
223
const { floatValue, formattedValue, value } = values;
224
const { event, source } = sourceInfo;
225
226
// Handle different value representations
227
onChange({
228
numeric: floatValue,
229
formatted: formattedValue,
230
raw: value
231
});
232
233
// Provide validation feedback
234
const isValid = floatValue !== undefined && floatValue > 0;
235
onValidation(isValid);
236
237
// Log changes from user input
238
if (source === 'event') {
239
console.log('User entered:', value);
240
}
241
};
242
243
return (
244
<NumberFormatBase
245
onValueChange={handleValueChange}
246
format={(value) => `$${value}`}
247
removeFormatting={(value) => value.replace('$', '')}
248
/>
249
);
250
}
251
```
252
253
### Validation and Filtering
254
255
Control what input is allowed with validation functions:
256
257
```typescript
258
// Restrict to positive numbers only
259
<NumberFormatBase
260
isAllowed={(values) => {
261
const { floatValue } = values;
262
return floatValue === undefined || floatValue >= 0;
263
}}
264
format={(value) => value}
265
removeFormatting={(value) => value}
266
/>
267
268
// Limit character input
269
<NumberFormatBase
270
isValidInputCharacter={(char) => /[0-9.]/.test(char)}
271
format={(value) => value}
272
removeFormatting={(value) => value}
273
/>
274
275
// Complex validation with error handling
276
function ValidatedInput({ max = 1000 }) {
277
const [error, setError] = useState('');
278
279
return (
280
<div>
281
<NumberFormatBase
282
isAllowed={(values) => {
283
const { floatValue } = values;
284
if (floatValue === undefined) return true;
285
286
if (floatValue > max) {
287
setError(`Value cannot exceed ${max}`);
288
return false;
289
}
290
291
setError('');
292
return true;
293
}}
294
format={(value) => value}
295
removeFormatting={(value) => value}
296
/>
297
{error && <div className="error">{error}</div>}
298
</div>
299
);
300
}
301
```
302
303
### Caret Positioning Control
304
305
Control cursor behavior with caret boundary functions:
306
307
```typescript { .api }
308
/**
309
* Function to determine valid caret positions
310
* @param formattedValue - The current formatted display value
311
* @returns Array of booleans where true indicates valid caret position
312
*/
313
type GetCaretBoundary = (formattedValue: string) => boolean[];
314
```
315
316
**Usage Examples:**
317
318
```typescript
319
// Only allow cursor in numeric positions of "$ 123.45"
320
function CurrencyCaretBoundary(formattedValue: string): boolean[] {
321
return formattedValue.split('').map((char, index) => {
322
// Allow cursor after $ and space, and at numeric positions
323
return index >= 2 || /[0-9.]/.test(char);
324
});
325
}
326
327
<NumberFormatBase
328
format={(value) => `$ ${value}`}
329
removeFormatting={(value) => value.replace(/[$ ]/g, '')}
330
getCaretBoundary={CurrencyCaretBoundary}
331
/>
332
```
333
334
### Character Comparison Logic
335
336
Define how characters are compared during formatting:
337
338
```typescript { .api }
339
/**
340
* Function to determine if characters represent the same logical value
341
*/
342
type IsCharacterSame = (compareProps: {
343
currentValue: string;
344
lastValue: string;
345
formattedValue: string;
346
currentValueIndex: number;
347
formattedValueIndex: number;
348
}) => boolean;
349
```
350
351
This is useful for advanced scenarios where logical characters might be represented differently in formatted vs unformatted states.