or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

customization.mdframework-integrations.mdindex.mdinput-components.mdinternationalization.mdphone-input-components.mdutility-functions.md

customization.mddocs/

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

```