DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
MediumJavaScript

Mastering the useFocus Hook: From React Fundamentals to Production-Grade Architecture

4 views

In the modern web, Focus Management is the invisible backbone of User Experience (UX) and Accessibility (a11y). Whether it’s auto-focusing a search bar when a modal opens, or highlighting a field during a validation error, controlling focus is a requirement for any professional React application.

This guide will deconstruct the useFocus hook, explain its internal mechanics, and provide real-world production scenarios that will help you ace your next Senior React Developer interview.


1. The "Why": Beyond Native Focus

You might wonder: “Why do I need a custom hook? Can’t I just use the :focus pseudo-class in CSS?”

While CSS handles styling well, JavaScript logic often needs to "know" the focus state to:

  1. Trigger Side Effects: Like fetching data when a user enters a field.

  2. Coordinate UI: For example, showing a complex dropdown menu only when an input is active.

  3. Programmatic Control: Moving the user's cursor automatically after an action (like clicking "Edit").


2. The Implementation: A 5/5 Rubric Approach

To score a 5/5 in an interview, your code must be performant, leak-proof, and ergonomic.

The Complete Code

JavaScript

import { useState, useRef, useEffect, useCallback } from 'react';

/**
 * useFocus Hook
 * @returns [ref, isFocused, setFocus]
 */
export function useFocus() {
  const [isFocused, setIsFocused] = useState(false);
  const elementRef = useRef(null);

  // 1. Stable Function Identity
  // We use useCallback so that if this function is passed to a memoized child,
  // it doesn't cause unnecessary re-renders.
  const setFocus = useCallback(() => {
    if (elementRef.current) {
      elementRef.current.focus();
    }
  }, []);

  useEffect(() => {
    // 2. Variable Capturing
    // We copy the current ref value to a local variable to ensure 
    // the cleanup function refers to the correct node during unmount.
    const node = elementRef.current;
    
    if (!node) return;

    const onFocus = () => setIsFocused(true);
    const onBlur = () => setIsFocused(false);

    // 3. Event Binding
    node.addEventListener('focus', onFocus);
    node.addEventListener('blur', onBlur);

    // 4. Robust Cleanup
    // This prevents memory leaks and "setting state on unmounted component" errors.
    return () => {
      node.removeEventListener('focus', onFocus);
      node.removeEventListener('blur', onBlur);
    };
  }, []); // Empty deps ensure this only runs once on mount

  return [elementRef, isFocused, setFocus];
}

3. Deep Dive: Interview "Must-Knows"

A. The Reference Stability Trap

In the code above, setFocus is wrapped in useCallback. In an interview, explain that if setFocus were a plain function, it would be "re-created" on every render. If you passed that function as a prop to a component wrapped in React.memo, that component would re-render needlessly.

B. The Cleanup Closure

Why do we do const node = elementRef.current inside the useEffect? React refs are mutable. By the time the cleanup function (the return block) runs, elementRef.current might have already been set to null. By capturing it in a local variable node when the effect starts, we ensure we always have the correct reference to remove the listener from.

C. Performance vs. State

Every time setIsFocused is called, the component using the hook re-renders. In high-performance applications (like a spreadsheet with 1,000 inputs), you might discuss using ref only for focus state to avoid re-renders, though useState is the standard for general UI reactivity.


4. Real-World Production Scenarios

To impress an interviewer, you must connect the code to business value. Here is how companies like Airbnb, Netflix, and Stripe use focus management.

Scenario A: The "Command+K" Global Search (SaaS Strategy)

In platforms like Slack or Discord, users navigate via keyboard.

  • The Problem: The user presses a shortcut, but the search input is in a different part of the DOM tree.

  • The Solution: The useFocus hook provides the setFocus method. When the global keydown event for "Cmd+K" is detected, the app calls setFocus().

  • Production Detail: Use the isFocused boolean to trigger an "active" class on the parent container, creating a "Glow" effect that CSS :focus can't easily reach if the input is nested deeply.

Scenario B: Multi-Factor Authentication (MFA) Inputs

When you receive a 6-digit code on your phone, banking apps like Revolut provide 6 individual boxes.

  • The Logic: As soon as the user types a digit in Box 1, the app validates the input and immediately calls setFocus() on Box 2.

  • The UI: The isFocused state is used to change the border color of the current active box, providing clear visual feedback.

Scenario C: Form Validation and Accessibility (WCAG)

Accessibility is a legal requirement for many companies.

  • The Use Case: If a user submits a long registration form and the "Email" field is invalid, the page shouldn't just show a red label. It should move the user's focus back to that field.

  • The Implementation: Using useFocus, you can programmatically snap the user back to the error, allowing screen readers to immediately announce the problematic field.


5. Advanced Interview Question: "What about Ref Forwarding?"

A common follow-up question is: "How do you use this hook if the input is a custom component, not a plain <input />?"

You must mention React.forwardRef. This allows your custom component to receive the ref from the hook and "forward" it down to the underlying HTML element.

JavaScript

const MyInput = React.forwardRef((props, ref) => (
  <input ref={ref} {...props} className="custom-input" />
));

function Parent() {
  const [inputRef, isFocused] = useFocus();
  return <MyInput ref={inputRef} />;
}

6. Comparison: useFocus vs. Native autoFocus

Interviewers love testing your knowledge of "Native vs. Synthetic."

  • Native autoFocus: Runs only on the initial page load. It is often unreliable in Single Page Applications (SPAs) where components mount/unmount without a page refresh.

  • useFocus (Our Hook): Gives you full control. You can trigger focus based on logic (e.g., "Focus only if the user is a first-time visitor") and handle cleanups properly.


7. The "Lead Developer" Perspective: Edge Cases

To truly score 100%, mention these two edge cases:

  1. Server-Side Rendering (SSR): Remind the interviewer that useEffect only runs on the client. Therefore, elementRef.current will be null on the server, and the hook safely handles this without crashing.

  2. Focus Trapping: In production modals, you don't just need to focus an element; you need to keep focus inside the modal. Explain how useFocus could be a building block for a useFocusTrap hook that prevents the user from "Tabbing" out of a popup.


Summary Checklist for the Interview

Rubric Category

Requirement

Why it matters

Correctness

Returns [ref, isFocused, setFocus]

Standard React hook pattern (similar to useState).

Cleanup

removeEventListener in return block

Prevents memory leaks in long-running SPAs.

Performance

useCallback for the setter function

Prevents unnecessary re-renders of child components.

Robustness

Check if (!node) before adding listeners

Prevents "Cannot read property of null" errors.

UX/A11y

Mentioning WCAG and focus shifting

Shows you care about the user, not just the code.


Final Thought

When implementing useFocus, you aren't just writing a utility; you are building a bridge between the user's intent and the browser's behavior. By focusing on stability and accessibility, you demonstrate the maturity required for high-level engineering roles.

Sample Test Cases

Case 1
Input
[]
Expected Output
{"isFocused": false, "focusCalled": false}
Case 2
Input
[]
Expected Output
{"isFocused": true, "focusCalled": true}
Case 3
Input
[]
Expected Output
{"isFocused": false, "focusCalled": true}

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
4
Likes
0
Solutions
0
Comments
0

Category

Frontend Engineering