0
# Customization and Styling
1
2
Extensive customization options for tailoring React Phone Number Input components to specific design requirements. The library provides comprehensive styling systems, custom component integration, and flexible configuration options.
3
4
## Capabilities
5
6
### CSS Styling System
7
8
Complete CSS styling system with custom properties and modifier classes.
9
10
```typescript { .api }
11
/**
12
* CSS stylesheet import for default styling
13
* Required for components with country selection dropdown
14
*/
15
import "react-phone-number-input/style.css";
16
17
/**
18
* CSS class structure and modifier classes
19
*/
20
interface CSSClasses {
21
/** Base component class */
22
".PhoneInput": CSSProperties;
23
/** Focus state modifier */
24
".PhoneInput--focus": CSSProperties;
25
/** Disabled state modifier */
26
".PhoneInput--disabled": CSSProperties;
27
/** Read-only state modifier */
28
".PhoneInput--readOnly": CSSProperties;
29
/** Country select dropdown */
30
".PhoneInputCountrySelect": CSSProperties;
31
/** Country select arrow */
32
".PhoneInputCountrySelectArrow": CSSProperties;
33
/** Country flag display */
34
".PhoneInputCountryFlag": CSSProperties;
35
/** Phone number input field */
36
".PhoneInputInput": CSSProperties;
37
}
38
```
39
40
**Basic Styling Usage:**
41
42
```typescript
43
import React, { useState } from "react";
44
import PhoneInput from "react-phone-number-input";
45
import "react-phone-number-input/style.css";
46
import "./custom-phone-input.css"; // Additional custom styles
47
48
function StyledExample() {
49
const [value, setValue] = useState();
50
return (
51
<PhoneInput
52
value={value}
53
onChange={setValue}
54
className="my-phone-input"
55
style={{
56
border: '2px solid #007bff',
57
borderRadius: '8px'
58
}}
59
/>
60
);
61
}
62
```
63
64
### CSS Custom Properties
65
66
Extensive CSS custom properties for fine-tuned styling control.
67
68
```typescript { .api }
69
/**
70
* Available CSS custom properties for customization
71
*/
72
interface CSSCustomProperties {
73
/** Country flag icon height */
74
"--PhoneInputCountryFlag-height"?: string;
75
/** Country flag icon border color */
76
"--PhoneInputCountryFlag-borderColor"?: string;
77
/** Country select arrow color */
78
"--PhoneInputCountrySelectArrow-color"?: string;
79
/** Country select arrow opacity (unfocused) */
80
"--PhoneInputCountrySelectArrow-opacity"?: string;
81
/** Focus state outline color */
82
"--PhoneInput-color--focus"?: string;
83
/** Component border color */
84
"--PhoneInput-borderColor"?: string;
85
/** Component background color */
86
"--PhoneInput-backgroundColor"?: string;
87
/** Input text color */
88
"--PhoneInput-color"?: string;
89
/** Placeholder text color */
90
"--PhoneInput-placeholderColor"?: string;
91
/** Component font size */
92
"--PhoneInput-fontSize"?: string;
93
/** Component padding */
94
"--PhoneInput-padding"?: string;
95
/** Component border radius */
96
"--PhoneInput-borderRadius"?: string;
97
}
98
```
99
100
**CSS Custom Properties Example:**
101
102
```css
103
/* Custom CSS file */
104
.custom-phone-input {
105
--PhoneInputCountryFlag-height: 1.2em;
106
--PhoneInputCountryFlag-borderColor: #ddd;
107
--PhoneInputCountrySelectArrow-color: #007bff;
108
--PhoneInputCountrySelectArrow-opacity: 0.8;
109
--PhoneInput-color--focus: #007bff;
110
--PhoneInput-borderColor: #ced4da;
111
--PhoneInput-backgroundColor: #fff;
112
--PhoneInput-color: #495057;
113
--PhoneInput-fontSize: 1rem;
114
--PhoneInput-padding: 0.75rem;
115
--PhoneInput-borderRadius: 0.375rem;
116
}
117
118
.custom-phone-input:hover {
119
--PhoneInput-borderColor: #007bff;
120
}
121
122
.custom-phone-input.PhoneInput--focus {
123
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
124
}
125
```
126
127
### Custom Input Components
128
129
Integration of custom input components with full prop forwarding.
130
131
```typescript { .api }
132
/**
133
* Custom input component interface
134
* Must use React.forwardRef() to forward ref to underlying input element
135
*/
136
interface CustomInputProps {
137
/** Current input value */
138
value: string;
139
/** Input change handler */
140
onChange(event: React.ChangeEvent<HTMLInputElement>): void;
141
/** Keyboard event handler for special key handling */
142
onKeyDown?(event: React.KeyboardEvent<HTMLInputElement>): void;
143
/** Paste event handler for formatting pasted content */
144
onPaste?(event: React.ClipboardEvent<HTMLInputElement>): void;
145
/** Standard input properties */
146
placeholder?: string;
147
disabled?: boolean;
148
readOnly?: boolean;
149
autoComplete?: string;
150
className?: string;
151
style?: React.CSSProperties;
152
onFocus?(event: React.FocusEvent<HTMLInputElement>): void;
153
onBlur?(event: React.FocusEvent<HTMLInputElement>): void;
154
// ... any other input props
155
}
156
157
type CustomInputComponent = React.ForwardRefExoticComponent<CustomInputProps & React.RefAttributes<HTMLInputElement>>;
158
159
interface InputComponentProps {
160
/** Custom input component */
161
inputComponent?: CustomInputComponent;
162
/** Additional props to pass to input component */
163
numberInputProps?: object;
164
}
165
```
166
167
**Custom Input Examples:**
168
169
```typescript
170
import React, { forwardRef } from "react";
171
import PhoneInput from "react-phone-number-input";
172
173
// Material-UI styled input
174
const MaterialInput = forwardRef<HTMLInputElement, any>((props, ref) => (
175
<input
176
{...props}
177
ref={ref}
178
className={`material-input ${props.className || ""}`}
179
style={{
180
border: 'none',
181
borderBottom: '2px solid #ddd',
182
borderRadius: 0,
183
padding: '8px 0',
184
fontSize: '16px',
185
backgroundColor: 'transparent',
186
outline: 'none',
187
...props.style
188
}}
189
/>
190
));
191
192
// Bootstrap styled input
193
const BootstrapInput = forwardRef<HTMLInputElement, any>((props, ref) => (
194
<input
195
{...props}
196
ref={ref}
197
className={`form-control ${props.className || ""}`}
198
/>
199
));
200
201
// Usage examples
202
function CustomInputExample() {
203
const [value, setValue] = useState();
204
return (
205
<PhoneInput
206
inputComponent={MaterialInput}
207
value={value}
208
onChange={setValue}
209
numberInputProps={{
210
style: { borderBottomColor: '#007bff' }
211
}}
212
/>
213
);
214
}
215
216
function BootstrapExample() {
217
const [value, setValue] = useState();
218
return (
219
<PhoneInput
220
inputComponent={BootstrapInput}
221
value={value}
222
onChange={setValue}
223
className="mb-3"
224
/>
225
);
226
}
227
```
228
229
### Custom Country Select Components
230
231
Replace the default country selection dropdown with custom implementations.
232
233
```typescript { .api }
234
/**
235
* Custom country select component interface
236
*/
237
interface CountrySelectProps {
238
/** Currently selected country */
239
value?: Country;
240
/** Country selection change handler */
241
onChange(country?: Country): void;
242
/** Available countries list */
243
options: Array<{
244
value?: Country;
245
label: string;
246
divider?: boolean;
247
}>;
248
/** Country labels for display */
249
labels: Labels;
250
/** Disabled state */
251
disabled?: boolean;
252
/** Read-only state */
253
readOnly?: boolean;
254
/** Custom styling */
255
className?: string;
256
style?: React.CSSProperties;
257
/** Accessibility properties */
258
"aria-label"?: string;
259
tabIndex?: number;
260
}
261
262
interface CountrySelectComponentProps {
263
/** Custom country select component */
264
countrySelectComponent?: React.ElementType;
265
/** Props to pass to country select component */
266
countrySelectProps?: object;
267
}
268
```
269
270
**Custom Country Select Examples:**
271
272
```typescript
273
import React from "react";
274
import PhoneInput from "react-phone-number-input";
275
276
// Custom dropdown with search
277
function SearchableCountrySelect({ value, onChange, options, labels, ...rest }) {
278
const [searchTerm, setSearchTerm] = useState("");
279
const [isOpen, setIsOpen] = useState(false);
280
281
const filteredOptions = options.filter(option =>
282
!searchTerm || labels[option.value]?.toLowerCase().includes(searchTerm.toLowerCase())
283
);
284
285
return (
286
<div className="custom-country-select" {...rest}>
287
<button
288
type="button"
289
onClick={() => setIsOpen(!isOpen)}
290
className="country-select-button"
291
>
292
{value ? labels[value] : "Select Country"}
293
</button>
294
295
{isOpen && (
296
<div className="country-dropdown">
297
<input
298
type="text"
299
placeholder="Search countries..."
300
value={searchTerm}
301
onChange={(e) => setSearchTerm(e.target.value)}
302
className="country-search"
303
/>
304
<div className="country-options">
305
{filteredOptions.map(option => (
306
<button
307
key={option.value || "international"}
308
type="button"
309
onClick={() => {
310
onChange(option.value);
311
setIsOpen(false);
312
}}
313
className="country-option"
314
>
315
{option.label}
316
</button>
317
))}
318
</div>
319
</div>
320
)}
321
</div>
322
);
323
}
324
325
// Usage with custom country select
326
function CustomCountrySelectExample() {
327
const [value, setValue] = useState();
328
return (
329
<PhoneInput
330
countrySelectComponent={SearchableCountrySelect}
331
countrySelectProps={{
332
className: "my-country-select"
333
}}
334
value={value}
335
onChange={setValue}
336
/>
337
);
338
}
339
```
340
341
### Custom Flag Components
342
343
Customize country flag display with custom flag components or flag sources.
344
345
```typescript { .api }
346
/**
347
* Flag component interfaces
348
*/
349
interface FlagProps {
350
/** Country code */
351
country: Country;
352
/** Country display name */
353
countryName: string;
354
/** Custom flag image URL */
355
flagUrl?: string;
356
/** Custom flag components map */
357
flags?: Flags;
358
/** Additional styling */
359
className?: string;
360
style?: React.CSSProperties;
361
}
362
363
interface EmbeddedFlagProps {
364
/** Accessibility title */
365
title: string;
366
/** Additional styling */
367
className?: string;
368
style?: React.CSSProperties;
369
}
370
371
type Flag = (props: FlagProps) => JSX.Element;
372
type EmbeddedFlag = (props: EmbeddedFlagProps) => JSX.Element;
373
type Flags = Partial<Record<Country, EmbeddedFlag>>;
374
375
interface FlagCustomizationProps {
376
/** Custom flag component renderer */
377
flagComponent?: Flag;
378
/** Base URL for flag images */
379
flagUrl?: string;
380
/** Custom embedded flag components */
381
flags?: Flags;
382
}
383
```
384
385
**Custom Flag Examples:**
386
387
```typescript
388
import React from "react";
389
import PhoneInput from "react-phone-number-input";
390
import flags from "react-phone-number-input/flags";
391
392
// Custom flag component with emoji
393
function EmojiFlag({ country, countryName, ...rest }: FlagProps) {
394
const flagEmoji = getFlagEmoji(country); // Your emoji lookup function
395
396
return (
397
<span
398
{...rest}
399
role="img"
400
aria-label={countryName}
401
className="emoji-flag"
402
>
403
{flagEmoji}
404
</span>
405
);
406
}
407
408
// Custom flag with image CDN
409
function ImageFlag({ country, countryName, ...rest }: FlagProps) {
410
return (
411
<img
412
{...rest}
413
src={`https://flagcdn.com/24x18/${country.toLowerCase()}.png`}
414
alt={countryName}
415
className="flag-image"
416
style={{ width: '24px', height: '18px' }}
417
/>
418
);
419
}
420
421
// Usage examples
422
function EmojiFlexExample() {
423
const [value, setValue] = useState();
424
return (
425
<PhoneInput
426
flagComponent={EmojiFlag}
427
value={value}
428
onChange={setValue}
429
/>
430
);
431
}
432
433
function CustomFlagUrlExample() {
434
const [value, setValue] = useState();
435
return (
436
<PhoneInput
437
flagUrl="https://flagpedia.net/data/flags/icon/72x54/"
438
value={value}
439
onChange={setValue}
440
/>
441
);
442
}
443
444
function MixedFlagsExample() {
445
const [value, setValue] = useState();
446
const customFlags = {
447
...flags,
448
US: ({ title, ...rest }) => <span {...rest}>๐บ๐ธ</span>,
449
CA: ({ title, ...rest }) => <span {...rest}>๐จ๐ฆ</span>
450
};
451
452
return (
453
<PhoneInput
454
flags={customFlags}
455
value={value}
456
onChange={setValue}
457
/>
458
);
459
}
460
```
461
462
### Container and Layout Customization
463
464
Customize the overall component layout and container structure.
465
466
```typescript { .api }
467
/**
468
* Container customization props
469
*/
470
interface ContainerCustomizationProps {
471
/** Custom container component */
472
containerComponent?: React.ElementType;
473
/** Props to pass to container component */
474
containerComponentProps?: object;
475
/** Component layout style */
476
style?: React.CSSProperties;
477
/** Component CSS class */
478
className?: string;
479
}
480
481
// Default container structure equivalent
482
function DefaultContainer({ className, style, children, ...rest }) {
483
return (
484
<div
485
className={`PhoneInput ${className || ""}`}
486
style={style}
487
{...rest}
488
>
489
{children}
490
</div>
491
);
492
}
493
```
494
495
**Container Customization Examples:**
496
497
```typescript
498
// Grid-based layout container
499
function GridContainer({ children, className, ...rest }) {
500
return (
501
<div
502
className={`phone-input-grid ${className || ""}`}
503
style={{
504
display: 'grid',
505
gridTemplateColumns: 'auto 1fr',
506
gap: '8px',
507
alignItems: 'center'
508
}}
509
{...rest}
510
>
511
{children}
512
</div>
513
);
514
}
515
516
// Flexbox layout container
517
function FlexContainer({ children, className, ...rest }) {
518
return (
519
<div
520
className={`phone-input-flex ${className || ""}`}
521
style={{
522
display: 'flex',
523
alignItems: 'stretch',
524
border: '1px solid #ddd',
525
borderRadius: '4px',
526
overflow: 'hidden'
527
}}
528
{...rest}
529
>
530
{children}
531
</div>
532
);
533
}
534
535
// Usage examples
536
function CustomContainerExample() {
537
const [value, setValue] = useState();
538
return (
539
<PhoneInput
540
containerComponent={GridContainer}
541
containerComponentProps={{
542
className: "my-grid-container"
543
}}
544
value={value}
545
onChange={setValue}
546
/>
547
);
548
}
549
```
550
551
### Theme Integration
552
553
Integration patterns for popular styling frameworks and design systems.
554
555
```typescript { .api }
556
// Theme integration interfaces
557
interface ThemeProps {
558
theme?: {
559
colors?: {
560
primary?: string;
561
border?: string;
562
background?: string;
563
text?: string;
564
focus?: string;
565
};
566
spacing?: {
567
sm?: string;
568
md?: string;
569
lg?: string;
570
};
571
borderRadius?: string;
572
fontSize?: string;
573
};
574
}
575
```
576
577
**Theme Integration Examples:**
578
579
```typescript
580
// Styled Components theme integration
581
import styled from "styled-components";
582
import PhoneInput from "react-phone-number-input";
583
584
const ThemedPhoneInput = styled(PhoneInput)`
585
--PhoneInput-color--focus: ${props => props.theme.colors.primary};
586
--PhoneInput-borderColor: ${props => props.theme.colors.border};
587
--PhoneInput-backgroundColor: ${props => props.theme.colors.background};
588
--PhoneInput-color: ${props => props.theme.colors.text};
589
--PhoneInput-fontSize: ${props => props.theme.fontSize};
590
--PhoneInput-borderRadius: ${props => props.theme.borderRadius};
591
--PhoneInput-padding: ${props => props.theme.spacing.md};
592
`;
593
594
// Tailwind CSS integration
595
function TailwindPhoneInput(props) {
596
return (
597
<div className="relative">
598
<PhoneInput
599
{...props}
600
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"
601
style={{
602
"--PhoneInput-color--focus": "#3b82f6",
603
"--PhoneInputCountryFlag-height": "1.25rem"
604
}}
605
/>
606
</div>
607
);
608
}
609
610
// CSS-in-JS integration
611
const phoneInputStyles = {
612
base: {
613
"--PhoneInput-borderColor": "#e5e7eb",
614
"--PhoneInput-backgroundColor": "#ffffff",
615
"--PhoneInput-color": "#374151",
616
"--PhoneInput-fontSize": "0.875rem",
617
"--PhoneInput-padding": "0.5rem 0.75rem",
618
"--PhoneInput-borderRadius": "0.375rem"
619
},
620
focus: {
621
"--PhoneInput-color--focus": "#3b82f6"
622
},
623
error: {
624
"--PhoneInput-borderColor": "#ef4444"
625
}
626
};
627
628
function CSSInJSExample({ error, ...props }) {
629
const styles = {
630
...phoneInputStyles.base,
631
...phoneInputStyles.focus,
632
...(error && phoneInputStyles.error)
633
};
634
635
return (
636
<PhoneInput
637
{...props}
638
style={styles}
639
/>
640
);
641
}
642
```