Building Your Learning Module...
Getting things ready for you!
Find videos you like?
Save to resource drawer for future reference!
useId is a Hook that generates a unique ID that is stable across server and client renders. It's perfect for connecting HTML elements with htmlFor attributes, ARIA attributes, and accessibility needs.
Connect labels with inputs using htmlFor and id attributes for screen readers
Link descriptive elements with interactive elements using aria-labelledby or aria-describedby
Generate unique IDs for reusable components that need internal element connections
Use useId whenever you need to connect HTML elements programmatically. Never use Math.random() or counters for IDs in React!
Call useId() to generate a unique ID that will be stable across server and client renders.
Pro Tip
Each useId() call generates a unique ID. Multiple calls in the same component will produce different IDs.
Use the generated ID to connect labels with inputs using htmlFor and id attributes.
Accessibility Win!
Screen readers will now announce "Name, edit text" when users focus on the input field.
Connect descriptive elements with interactive elements using ARIA attributes for enhanced accessibility.
Screen Reader Magic
Screen readers will announce the input and then read the associated error message automatically.
Build reusable components that generate their own unique IDs, preventing conflicts when used multiple times.
No ID Conflicts!
Each Checkbox instance gets its own unique ID, preventing conflicts and ensuring proper accessibility.
Follow these guidelines to use useId effectively and avoid common pitfalls.
Golden Rule
Use useId only for connecting HTML elements. For list keys, use stable identifiers from your data.
Complete form with proper accessibility connections
function FormField({ label, type = 'text', error, required = false }) {
const id = useId();
const errorId = useId();
return (
<div className="form-field">
<label htmlFor={id}>
{label}
{required && <span className="required">*</span>}
</label>
<input
id={id}
type={type}
aria-describedby={error ? errorId : undefined}
aria-invalid={error ? 'true' : 'false'}
required={required}
/>
{error && (
<div id={errorId} className="error-message" role="alert">
{error}
</div>
)}
</div>
);
}
function SignUpForm() {
const [formData, setFormData] = React.useState({
name: '',
email: '',
password: ''
});
const [errors, setErrors] = React.useState({});
const validateForm = () => {
const newErrors = {};
if (!formData.name.trim()) {
newErrors.name = 'Name is required';
}
if (!formData.email.trim()) {
newErrors.email = 'Email is required';
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Email is invalid';
}
if (!formData.password) {
newErrors.password = 'Password is required';
} else if (formData.password.length < 8) {
newErrors.password = 'Password must be at least 8 characters';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validateForm()) {
alert('Form submitted successfully!');
setFormData({ name: '', email: '', password: '' });
setErrors({});
}
};
const handleChange = (field) => (e) => {
setFormData(prev => ({ ...prev, [field]: e.target.value }));
// Clear error when user starts typing
if (errors[field]) {
setErrors(prev => ({ ...prev, [field]: '' }));
}
};
return (
<div className="container">
<div className="form-header">
<h1>🔐 Create Account</h1>
<p>Join us today! All fields are required.</p>
</div>
<form onSubmit={handleSubmit} className="signup-form">
<FormField
label="Full Name"
value={formData.name}
onChange={handleChange('name')}
error={errors.name}
required
/>
<FormField
label="Email Address"
type="email"
value={formData.email}
onChange={handleChange('email')}
error={errors.email}
required
/>
<FormField
label="Password"
type="password"
value={formData.password}
onChange={handleChange('password')}
error={errors.password}
required
/>
<div className="form-actions">
<button type="submit" className="submit-btn">
Sign Up
</button>
</div>
</form>
<div className="accessibility-info">
<h2>♿ Accessibility Features</h2>
<ul>
<li>✅ All form fields have proper label connections</li>
<li>✅ Error messages are announced by screen readers</li>
<li>✅ Required fields are clearly marked</li>
<li>✅ Form validation provides helpful feedback</li>
<li>✅ Unique IDs prevent conflicts</li>
</ul>
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<SignUpForm />);Loading preview...
Each useId() call generates a unique identifier that won't conflict with other IDs.
IDs are stable across server and client rendering, preventing hydration mismatches.
Lightweight and fast - no performance overhead compared to manual ID generation.