useComponentId
Get a unique identifier for each component instance.
Overview
useComponentId generates a unique ID for each component instance, useful for debugging, tracking, and identifying specific components in large applications.
API
const id = useComponentId(componentName?: string);
Parameters:
componentName: Optional prefix for the ID (default: 'component')
Returns:
string: Unique ID like"component-1","MyComponent-5"
Basic Example
import { useComponentId } from 'react-dev-debugger';
function Card() {
const id = useComponentId('Card');
console.log(`Card instance: ${id}`); // "Card-1", "Card-2", etc.
return <div id={id}>Card Content</div>;
}
Live Playground
Component Instances
Multiple Instances
Card 1
Card-1Count: 0
Renders: 0
Card 2
Card-2Count: 0
Renders: 0
function Card() {
const id = useComponentId('Card');
console.log('Card ID:', id);
// Card-1, Card-2, Card-3, etc.
return <div id={id}>Card Content</div>;
}Dynamic Components
Button
ButtonComponent-3Instance #1
Input
InputComponent-4Instance #2
Select
SelectComponent-5Instance #3
function DynamicWidget({ type }) {
const id = useComponentId(`${type}Widget`);
useEffect(() => {
console.log(`[${id}] Mounted`);
return () => console.log(`[${id}] Unmounted`);
}, [id]);
return <div id={id}>{type} Widget</div>;
}Accessibility Example
function FormField({ label, name }) {
const fieldId = useComponentId(`FormField-${name}`);
return (
<div>
<label htmlFor={fieldId}>{label}</label>
<input
id={fieldId}
name={name}
aria-describedby={`${fieldId}-hint`}
/>
<span id={`${fieldId}-hint`}>Helper text</span>
</div>
);
}Component IDs
How it works:
- Each component gets unique ID on mount
- ID persists across re-renders
- Format:
prefix-number - Useful for debugging and tracking
Use Cases
- Accessibility: Generate unique IDs for labels and ARIA attributes
- Debugging: Track specific component instances in logs
- Analytics: Identify which instance triggered events
- Testing: Use as stable test IDs
API
// Basic usage
const id = useComponentId();
// "component-1"
// With prefix
const id = useComponentId('Card');
// "Card-1"
// With component name
const id = useComponentId('UserProfile');
// "UserProfile-1"Best Practices:
- Use descriptive prefixes
- Don't use as React keys
- Perfect for ARIA IDs
- Great for debugging logs
Advanced Examples
List Items
function TodoList({ todos }: { todos: Todo[] }) {
return (
<ul>
{todos.map(todo => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
);
}
function TodoItem({ todo }: { todo: Todo }) {
const componentId = useComponentId('TodoItem');
useEffect(() => {
console.log(`${componentId} mounted`);
return () => console.log(`${componentId} unmounted`);
}, [componentId]);
return (
<li data-component-id={componentId}>
{todo.text}
</li>
);
}
Dynamic Components
function DynamicWidget({ type }: { type: string }) {
const id = useComponentId(`Widget-${type}`);
useEffect(() => {
// Track widget lifecycle
analytics.track('widget_mounted', {
componentId: id,
widgetType: type,
});
}, [id, type]);
return (
<div id={id} className={`widget-${type}`}>
<h3>Widget {id}</h3>
</div>
);
}
Modal Tracking
function Modal({ title, children }: ModalProps) {
const modalId = useComponentId('Modal');
useEffect(() => {
console.log(`Modal ${modalId} opened: ${title}`);
return () => {
console.log(`Modal ${modalId} closed`);
};
}, [modalId, title]);
return (
<div
id={modalId}
className="modal"
aria-labelledby={`${modalId}-title`}
>
<h2 id={`${modalId}-title`}>{title}</h2>
{children}
</div>
);
}
Form Fields
function FormField({
label,
name,
value,
onChange
}: FormFieldProps) {
const fieldId = useComponentId(`FormField-${name}`);
return (
<div className="form-field">
<label htmlFor={fieldId}>{label}</label>
<input
id={fieldId}
name={name}
value={value}
onChange={onChange}
aria-describedby={`${fieldId}-error`}
/>
<span id={`${fieldId}-error`} className="error" />
</div>
);
}
Error Boundaries
function ComponentWithErrorBoundary() {
const componentId = useComponentId('TrackedComponent');
const handleError = useCallback((error: Error) => {
console.error(`Error in ${componentId}:`, error);
// Report to error tracking service
errorTracker.report({
componentId,
error: error.message,
stack: error.stack,
});
}, [componentId]);
return (
<ErrorBoundary onError={handleError}>
<YourComponent />
</ErrorBoundary>
);
}
Debugging Features
Component Lifecycle
Track component instances:
function TrackedComponent() {
const id = useComponentId('TrackedComponent');
useEffect(() => {
console.log(`[${id}] Mounted`);
return () => {
console.log(`[${id}] Unmounted`);
};
}, [id]);
useEffect(() => {
console.log(`[${id}] Updated`);
});
return <div>{id}</div>;
}
Performance Monitoring
function PerformanceMonitored() {
const id = useComponentId('PerformanceMonitored');
useEffect(() => {
const startTime = performance.now();
return () => {
const endTime = performance.now();
const duration = endTime - startTime;
console.log(`${id} lifetime: ${duration}ms`);
};
}, [id]);
return <div>Content</div>;
}
Analytics Integration
function AnalyticsTracked() {
const id = useComponentId('AnalyticsTracked');
useEffect(() => {
analytics.track('component_view', {
componentId: id,
timestamp: Date.now(),
});
}, [id]);
return <div>Tracked content</div>;
}
Best Practices
✅ Do's
- Use descriptive prefixes:
'UserCard'instead of'comp' - Combine with component name: Makes debugging easier
- Use for accessibility: Generate unique IDs for ARIA attributes
- Track component lifecycle: Log mount/unmount events
❌ Don'ts
- Don't use as React key: Use stable IDs from data instead
- Don't rely on ID format: Implementation may change
- Don't use for business logic: Only for debugging/tracking
- Don't generate IDs outside components: Hook must be called in component
Use Cases
Accessibility
function Accordion() {
const accordionId = useComponentId('Accordion');
return (
<div>
<button
id={`${accordionId}-trigger`}
aria-controls={`${accordionId}-content`}
aria-expanded="false"
>
Toggle
</button>
<div
id={`${accordionId}-content`}
aria-labelledby={`${accordionId}-trigger`}
>
Content
</div>
</div>
);
}
Testing
function TestableComponent() {
const id = useComponentId('TestableComponent');
return (
<div data-testid={id}>
<button data-testid={`${id}-button`}>Click</button>
</div>
);
}
// In tests:
test('renders component', () => {
render(<TestableComponent />);
expect(screen.getByTestId(/TestableComponent-\d+/)).toBeInTheDocument();
});
Debug Logging
function DebugComponent({ value }: { value: number }) {
const id = useComponentId('DebugComponent');
useEffect(() => {
console.log(`[${id}] Value changed:`, value);
}, [id, value]);
return <div>{value}</div>;
}
TypeScript Support
Full type safety:
function TypedComponent<T>({ data }: { data: T }) {
const id: string = useComponentId('TypedComponent');
useEffect(() => {
console.log(`${id} received data:`, data);
}, [id, data]);
return <div id={id}>Content</div>;
}
Component Identification
function ComponentTree() {
const parentId = useComponentId('Parent');
return (
<div id={parentId}>
<Child parentId={parentId} />
<Child parentId={parentId} />
</div>
);
}
function Child({ parentId }: { parentId: string }) {
const childId = useComponentId('Child');
console.log(`${childId} is child of ${parentId}`);
return <div id={childId}>Child</div>;
}
Multiple Instances
function ComponentFactory() {
return (
<>
<Card /> {/* Card-1 */}
<Card /> {/* Card-2 */}
<Card /> {/* Card-3 */}
</>
);
}
function Card() {
const id = useComponentId('Card');
return (
<div id={id}>
Card instance: {id}
</div>
);
}
Next Steps
- useRenderTracking - Track component renders
- Inspector View - Inspect component details
- Panel - Debug panel overview