Background
While developing the English word dictation tool, I found an input-method-related issue: when the user switched to a Chinese input method, they could type Chinese characters into the input box, which was not the intended behavior. The expected behavior is that regardless of the input method, only letters can be entered, and the experience should feel as smooth as using an English input method.
Problem analysis
-
Locating the problem: in the WordDictation.jsx component, the input’s onChange handler didn’t validate incoming characters, so any character (including Chinese) could be entered.
-
Root causes:
- The input’s maxLength was set to 1, but the character type wasn’t restricted
- The onChange handler accepted and processed all input without filtering characters
- No regex validation existed to ensure only letters could be entered
-
Extra findings:
- Audio didn’t play on initial load (a condition-checking problem)
- On initial load a mouse click was needed to start typing (an auto-focus problem)
The solution
1. Fixing the Chinese input method issue
Add letter validation to the input’s onChange handler, allowing only a-z and A-Z:
onChange={(e) => {
const inputValue = e.target.value;
// only allow letters
if (/^[a-zA-Z]$/.test(inputValue)) {
const newInput = userInput.split('');
newInput[index] = inputValue.toLowerCase();
const updatedInput = newInput.join('');
setUserInput(updatedInput);
// auto-focus the next input
setTimeout(() => {
if (inputValue && index < currentWord.word.length - 1) {
const nextWrapper = e.target.parentElement.nextElementSibling;
const nextInput = nextWrapper?.querySelector('input');
if (nextInput) {
nextInput.focus();
nextInput.select();
}
}
}, 0);
// if all letters are entered, auto-trigger answer check
if (updatedInput.length === currentWord.word.length && !showAnswer) {
setTimeout(() => {
checkAnswer();
}, 300);
}
}
}}
2. Fixing the audio playback issue
Modify the audio playback useEffect condition so audio also plays on initial load:
useEffect(() => {
if (currentWord) { // play audio as long as the current word exists
const timer = setTimeout(() => {
playWord();
}, 150); // give state reset some time
return () => clearTimeout(timer);
}
}, [currentIndex, currentWord]);
3. Fixing the auto-focus issue
Optimize the auto-focus logic so the first input correctly receives focus on initial load:
useEffect(() => {
// delay focus to ensure the DOM has rendered
const timer = setTimeout(() => {
if (!showAnswer) {
// prefer focusing the first input via ref, ensuring focus on initial load
if (inputRef.current && userInput.length === 0) {
inputRef.current.focus();
} else {
// find the next position that should receive input
const nextInputIndex = userInput.length;
// use a more precise selector
const inputs = document.querySelectorAll('.letter-input');
const targetInput = inputs[Math.min(nextInputIndex, inputs.length - 1)];
if (targetInput) {
targetInput.focus();
if (targetInput.value) {
targetInput.select();
}
}
}
}
}, 150); // increase the delay to ensure the DOM is fully rendered
return () => clearTimeout(timer);
}, [currentIndex, isFullscreen, showAnswer, userInput.length]);
Result
-
Input method issue resolved: even if the user switches to a Chinese input method, only letter characters can be typed, with no perceptible difference — it feels like using an English input method.
-
Audio plays correctly: the current word’s audio auto-plays on initial load, and plays normally when switching words.
-
Auto-focus works: on initial load focus automatically goes to the first input, so typing works without a mouse click — a better user experience.
Technical takeaways
-
Input validation: use the regex
/^[a-zA-Z]$/for strict character validation, ensuring only letters can be entered. -
User experience optimization:
- Auto-focus the next input to improve typing efficiency
- Auto-trigger the answer check to reduce user actions
- Keep consistent case handling to improve recognition accuracy
-
State management: use the useEffect hook sensibly to handle component state changes and side effects.
-
DOM operations: ensure operations run after the DOM is fully rendered to avoid problems from elements not yet loaded.
Summary
Through this fix, we resolved the input-method issue in the English word dictation tool, ensuring only letters can be entered regardless of the input method. We also optimized audio playback and auto-focus, improving the overall user experience.
The lessons from solving this problem:
- For input boxes, besides setting maxLength, also restrict the character type per requirements
- Regex is an effective tool for input validation — use it where appropriate
- Component state handling on initial load deserves special attention
- Auto-focus significantly improves UX and should be used in suitable scenarios
This fix not only solved the immediate problem but also provides reference experience for handling similar issues in the future.