Part 23: Advanced Hooks: useId & useImperativeHandle

Part 23 Technology Updated September 12, 2026

Part 23: Advanced Hooks: useId & useImperativeHandle

React provides specialized hooks for accessibility and fine-grained ref customization.


1. useId: Accessible Unique IDs

useId generates unique, collision-free identifiers that are consistent between server-side rendering (SSR) and client hydration.

import { useId } from 'react';

export default function FormField({ label, type = "text" }) {
  const id = useId();

  return (
    <div className="field-wrapper mb-3">
      <label htmlFor={id} className="block font-semibold">{label}</label>
      <input id={id} type={type} className="border p-2 rounded w-full" />
    </div>
  );
}

2. useImperativeHandle + forwardRef

By default, parent components should not access child component internals. However, for specialized widgets (like video players or custom text editors), you can expose specific imperative methods using forwardRef and useImperativeHandle:

import { forwardRef, useRef, useImperativeHandle } from 'react';

const CustomVideoPlayer = forwardRef((props, ref) => {
  const videoRef = useRef(null);

  useImperativeHandle(ref, () => ({
    playVideo() {
      videoRef.current.play();
    },
    pauseVideo() {
      videoRef.current.pause();
    },
    resetVideo() {
      videoRef.current.currentTime = 0;
    }
  }));

  return (
    <video ref={videoRef} src={props.src} className="rounded shadow" />
  );
});

export default function Dashboard() {
  const playerRef = useRef(null);

  return (
    <div>
      <CustomVideoPlayer ref={playerRef} src="/promo.mp4" />
      <div className="mt-4 flex gap-2">
        <button onClick={() => playerRef.current.playVideo()}>Play</button>
        <button onClick={() => playerRef.current.pauseVideo()}>Pause</button>
        <button onClick={() => playerRef.current.resetVideo()}>Reset</button>
      </div>
    </div>
  );
}

Key Takeaways

  • Use useId for generating SSR-safe unique HTML attribute IDs for forms and ARIA.
  • Use useImperativeHandle with forwardRef to expose controlled imperative methods to parent refs.

In Part 24, we will learn how to build reusable Custom Hooks!