useDebugValue adds a readable label to a custom Hook in React DevTools. It shows intent when you inspect a component, instead of forcing you to read raw internal data. The label is developer-only and never appears in the rendered UI.
Label a custom Hook
Call useDebugValue at the top level of the Hook with the value you want DevTools to show next to the Hook name.
import { useDebugValue, useState } from "react";
function useCounter(initialValue) {
const [count, setCount] = useState(initialValue);
useDebugValue(count === 0 ? "empty" : "counting");
return [count, setCount];
}In React DevTools, a component using this Hook now shows a label like Counter: "empty" or Counter: "counting" next to the Hook. Without the call, DevTools would show only the raw number.
The label is static text for debugging, so it does not affect rendering. Only custom Hooks may call it, so it belongs inside the Hook body, never in a component.
Defer expensive formatting
Passing a second argument turns it into a formatting function that runs only when the Hook is inspected.
useDebugValue(items, (list) => list.length + " items");The function receives the debug value and returns the display text. Because it runs lazily, the Hook avoids calling a costly formatter on every render and only pays the cost inside DevTools.
Pass this formatter when the raw value is a large array or an object that is expensive to stringify. For simple values, skip the formatter and pass the value directly.
When useDebugValue is worth it
Do not add a debug value to every Hook. It matters most for shared library Hooks whose internal state is large or hard to inspect, where a short label saves the next developer real time.
- Use a short, human-readable label over a raw object.
- Reach for the format function only when formatting is expensive.
- Skip it when the underlying value is already obvious.
A label is developer tooling, not part of the public API of the Hook. The label should answer a question at a glance, not dump every field of the Hook. A good label reads like a status word rather than a data dump.
See the label in DevTools
Open React DevTools and select a component that calls the Hook. The label appears in the Hooks panel beside the Hook name, and it updates on every render like the values around it. The first argument is evaluated on every render, so keep it cheap and reserve the formatter for anything heavy.
See how to create a custom Hook for the extraction steps, and React Developer Tools for where the label appears.
Rune AI
Key Insights
- Call useDebugValue at the top level of a custom Hook.
- The first argument is the value shown in DevTools.
- The optional second argument is a formatting function.
- Format functions run only when the Hook is inspected.
- Use it for shared Hooks with complex internal state.
Frequently Asked Questions
What does useDebugValue do?
Where can useDebugValue be called?
When should I skip useDebugValue?
Conclusion
useDebugValue gives a custom Hook a readable label in React DevTools, so inspecting a component shows intent instead of raw data. Pass a format function to defer expensive formatting until the Hook is actually inspected.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.