Home
React
Advanced Hook: flushSync()
Daniel Nguyen
Daniel Nguyen
July 17, 2025
1 min

Focus management is essential for interactive React UIs, especially forms, modals, and dynamically rendered components.

Proper focus management improves keyboard navigation, accessibility, and user experience.

1. The Problem: Focusing an Element Before It Exists

function MyComponent() {
const inputRef = useRef<HTMLInputElement>(null)
const [show, setShow] = useState(false)
return (
<div>
<button
onClick={() => {
setShow(true)
inputRef.current?.focus()
}}
>
Show
</button>
{show && <input ref={inputRef} />}
</div>
)
}

Why doesn’t this work?

Calling setShow(true) requests a state update. React has not yet committed the new input to the DOM when the next line executes, so inputRef.current is still null.

Focus the input after React commits the DOM update.

function MyComponent() {
const inputRef = useRef<HTMLInputElement>(null)
const [show, setShow] = useState(false)
useEffect(() => {
if (show) {
inputRef.current?.focus()
}
}, [show])
return (
<div>
<button onClick={() => setShow(true)}>
Show
</button>
{show && <input ref={inputRef} />}
</div>
)
}

When show becomes true, React renders the input, attaches the ref, and then runs the effect.

This is usually sufficient for focus management because focusing an input does not generally require a synchronous DOM update within the click handler.

3. Alternative: autoFocus

For a simple conditionally rendered input, you can also use:

{show && <input autoFocus />}

React will attempt to focus the input when it mounts. For more complex focus behavior, an explicit ref and effect provide greater control.

4. When Should You Use flushSync?

flushSync forces React to flush updates synchronously so the DOM is updated before the next statement executes.

import { flushSync } from 'react-dom'
function MyComponent() {
const inputRef = useRef<HTMLInputElement>(null)
const [show, setShow] = useState(false)
return (
<div>
<button
onClick={() => {
flushSync(() => {
setShow(true)
})
inputRef.current?.focus()
}}
>
Show
</button>
{show && <input ref={inputRef} />}
</div>
)
}

This works because the input has been committed to the DOM before focus() executes.

However, flushSync can hurt performance and may force pending work or effects to run synchronously. Use it only when an integration or imperative operation genuinely requires the DOM to be updated immediately.


Tags

#ReactAdvancedHooks

Share

Daniel Nguyen

Daniel Nguyen

Frontend Developer

Frontend developer specializing in React, Next.js, and JavaScript. Writing practical guides on modern web development at Dev98.

Expertise

React
Next.js
JavaScript
TypeScript
Python

Social Media

githublinkedinyoutubewebsite

Related Posts

Advanced Hook
Advanced Hook: useSyncExternalStore()
July 19, 2025
1 min
Dev98

Dev98

React · Next.js · Web development