React Curriculum

Complex Input Patterns: Files & Input Masking

Hard100% Free~30 mins#react#file-upload#masked-inputs#cursor-management#createobjecturl#memory-leaks
Interview Answer (30-Second Summary)

Complex inputs require specialized DOM handling: file inputs (<input type="file">) are strictly uncontrolled and managed via refs and FormData, while masked inputs (phone numbers, credit cards) require tracking cursor selection ranges to prevent the caret from jumping during format insertion.

Key Learning Objectives
✓

Manage single and multi-file uploads accessibly with drag-and-drop and progress states.

✓

Implement phone number and credit card masked inputs that preserve cursor position.

✓

Handle file size, MIME type validation, and preview generation using URL.createObjectURL.

✓

Clean up object URLs on component unmount to prevent memory leaks.

The Interview Problem & Context

Implement a masked phone number input component (format: (XXX) XXX-XXXX) that formats numbers as the user types while preserving the caret cursor position.

1import React, { useRef, useState, useLayoutEffect } from 'react';
2
3function formatPhone(digits: string): string {
4 const clean = digits.replace(/\D/g, '').slice(0, 10);
5 if (clean.length <= 3) return clean;
6 if (clean.length <= 6) return `(${clean.slice(0, 3)}) ${clean.slice(3)}`;
7 return `(${clean.slice(0, 3)}) ${clean.slice(3, 6)}-${clean.slice(6)}`;
8}
9
10export function MaskedPhoneInput() {
11 const [value, setValue] = useState('');
12 const inputRef = useRef<HTMLInputElement>(null);
13 const cursorRef = useRef<number | null>(null);
14
15 function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
16 const input = e.target;
17 cursorRef.current = input.selectionStart; // Record cursor position before format
18 setValue(formatPhone(input.value));
19 }
20
21 useLayoutEffect(() => {
22 // Restore cursor position synchronously before paint
23 if (inputRef.current && cursorRef.current !== null) {
24 inputRef.current.setSelectionRange(cursorRef.current, cursorRef.current);
25 }
26 }, [value]);
27
28 return (
29 <input
30 ref={inputRef}
31 type="tel"
32 value={value}
33 onChange={handleChange}
34 placeholder="(555) 000-0000"
35 />
36 );
37}
Deep Architectural Explanation

Handling Complex Input Patterns

1. Input Masking & Caret Preservation

When formatting strings (adding parentheses, spaces, dashes):

  • Programmatically setting input.value forces the browser caret to the end of the input.
  • Solution:
    1. Record input.selectionStart before state update.
    2. Apply the format transformation.
    3. Inside useLayoutEffect (synchronously before paint), call input.setSelectionRange(pos, pos).
    4. The user sees seamless formatting without the cursor jumping away from their active editing position!

2. File Uploads & Memory Safety

File inputs cannot be controlled (value cannot be set programmatically):

tsx
<input type="file" ref={fileInputRef} onChange={handleFile} />
  • When displaying previews of selected images:
ts
const previewUrl = URL.createObjectURL(file);
  • Memory Leak Alert: Browser memory keeps this blob reference alive until the tab closes. Always revoke it in useEffect cleanup:
ts
return () => URL.revokeObjectURL(previewUrl);
Common Interview Traps & Pitfalls
✕

Using useEffect to restore cursor position, causing visible cursor jumping and visual jitter.

✕

Creating object URLs with URL.createObjectURL without revoking them, causing browser memory leaks.

✕

Attempting to pass value={fileState} to a file input, which throws a DOM security error.

Senior Interviewer Follow-Up Probes
?

How do you calculate the new cursor position when formatting characters (like parentheses) are inserted before the cursor?

?

How do you handle drag-and-drop file zones with onDragOver and onDrop in React?

?

How do you track upload progress percentages with XMLHttpRequest or fetch streams?

Frequently Asked Interview Questions
Why are file inputs always uncontrolled in React?

For browser security reasons, JavaScript cannot set the value of an <input type="file"> to prevent malicious scripts from uploading unauthorized files from a user's hard drive.

useLayoutEffect runs synchronously before browser paint, ensuring the cursor position is restored before the frame renders so the user never sees the caret jump.

Use URL.createObjectURL(file) to generate a temporary local blob URL to pass to an <img src="..." /> tag.

Each call to createObjectURL holds the file in browser memory until explicitly released. Revoking it prevents memory leaks when uploading large images.

A technique that automatically formats user input into an expected visual pattern (like phone numbers, dates, or credit card numbers) as they type.