PasswordInput
** Last Built**: September 2, 2025 at 4:19 PM A specialized password input component with show/hide toggle, strength indicator, and validation features. Follows React Admin patterns and provides enhanced password input functionality.
Overview
The PasswordInput component is designed for secure password entry with built-in visibility toggle, character counting, and accessibility features. It's perfect for login forms, registration forms, and any interface requiring password input with enhanced user experience.
Features
- Show/Hide Toggle: Eye icon button to toggle password visibility
- Character Count: Optional character count display with max length
- Accessibility: Full ARIA support, keyboard navigation, and screen reader compatibility
- Loading State: Built-in loading indicator and disabled state handling
- Validation Support: Error display and helper text
- Theme Integration: Consistent styling with Tailwind CSS
- TypeScript: Fully typed with comprehensive prop interfaces
Basic Usage
// Component is available in the live scope
function LoginForm() {
const [password, setPassword] = useState('');
return (
<PasswordInput
label='Password'
value={password}
onChange={e => setPassword(e.target.value)}
placeholder='Enter your password'
required
/>
);
}
Props
| Prop | Type | Default | Description |
| ----------------------------------- |
| label | string | - | Label text for the input |
| helperText | string | - | Helper text below the input |
| error | string | - | Error message to display |
| required | boolean | false | Whether the field is required |
| size | 'sm' \| 'md' \| 'lg' | 'md' | Input size variant |
| loading | boolean | false | Whether to show a loading state |
| leftIcon | ReactNode | - | Icon to display on the left side |
| showCharacterCount | boolean | false | Whether to show character count |
| maxLength | number | - | Maximum character limit |
| disabled | boolean | false | Whether the input is disabled |
| readOnly | boolean | false | Whether the input is read-only |
| showStrengthIndicator | boolean | false | Whether to show password strength |
| validateStrength | (password: string) => object | - | Custom strength validation function |
| minLength | number | - | Minimum password length requirement |
| showRequirements | boolean | false | Whether to show requirements list |
| requirements | object | - | Custom password requirements |
Examples
Basic Password Input
<PasswordInput label='Password' placeholder='Enter your password' required />
With Character Count
<PasswordInput
label='Password'
showCharacterCount
maxLength={20}
helperText='Password must be between 8-20 characters'
/>
With Left Icon
import { Lock } from 'lucide-react';
<PasswordInput
label='Password'
leftIcon={<Lock className='h-5 w-5' />}
placeholder='Enter your password'
/>;
With Error State
<PasswordInput
label='Password'
error='Password must be at least 8 characters long'
helperText='Include uppercase, lowercase, numbers, and special characters'
/>
Loading State
<PasswordInput
label='Password'
loading
helperText='Validating password strength...'
/>
Disabled State
<PasswordInput
label='Password'
disabled
helperText='Password field is currently disabled'
/>
Password Visibility Toggle
The component automatically includes a show/hide password toggle button on the right side:
<PasswordInput
label='Password'
helperText='Click the eye icon to show/hide your password'
/>
- Default State: Password is hidden (type="password")
- Toggle Button: Eye icon that changes to EyeOff when clicked
- Accessibility: Proper ARIA labels ("Show password" / "Hide password")
- Disabled State: Toggle is disabled when input is disabled or readonly
Character Count
Enable character counting to help users stay within password limits:
<PasswordInput
label='Password'
showCharacterCount
maxLength={16}
helperText='Maximum 16 characters allowed'
/>
- Display Format: "5/16" (current/maximum)
- Real-time Updates: Count updates as user types
- Max Length Enforcement: Browser prevents input beyond limit
Accessibility Features
The PasswordInput component follows accessibility best practices:
ARIA Attributes
aria-invalid: Set to "true" when error is presentaria-describedby: Links to helper text and error messagesaria-label: Dynamic labels for show/hide toggle button
Keyboard Navigation
- Tab Order: Input field → Toggle button → Next element
- Enter/Space: Activates toggle button when focused
- Escape: Returns focus to input field
Screen Reader Support
- Label Association: Proper label-input association
- State Announcements: Dynamic announcements for show/hide state
- Error Reporting: Error messages announced immediately
State Management
Controlled vs Uncontrolled
// Controlled component
const [password, setPassword] = useState('');
<PasswordInput
value={password}
onChange={e => setPassword(e.target.value)}
/>
// Uncontrolled component
<PasswordInput
defaultValue="initial-password"
onChange={handleChange}
/>
Loading State
const [isLoading, setIsLoading] = useState(false);
<PasswordInput
label='Password'
loading={isLoading}
helperText={isLoading ? 'Validating...' : 'Enter your password'}
/>;
Validation and Error Handling
Basic Validation
const [error, setError] = useState('');
const validatePassword = password => {
if (password.length < 8) {
setError('Password must be at least 8 characters');
return false;
}
setError('');
return true;
};
<PasswordInput
label='Password'
error={error}
onChange={e => validatePassword(e.target.value)}
/>;
Custom Requirements
<PasswordInput
label='Password'
showRequirements
requirements={{
minLength: 8,
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
requireSpecialChars: true,
}}
helperText='Password must meet all requirements'
/>
Integration with Forms
React Hook Form
import { useForm } from 'react-hook-form';
function PasswordForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<PasswordInput
label='Password'
error={errors.password?.message}
{...register('password', {
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
})}
/>
<button type='submit'>Submit</button>
</form>
);
}
Formik
import { Formik, Form, Field } from 'formik';
function PasswordForm() {
return (
<Formik
initialValues={{ password: '' }}
onSubmit={values => console.log(values)}
>
<Form>
<Field name='password'>
{({ field, meta }) => (
<PasswordInput
label='Password'
error={meta.touched && meta.error}
{...field}
/>
)}
</Field>
<button type='submit'>Submit</button>
</Form>
</Formik>
);
}
Styling and Customization
Custom Classes
<PasswordInput
label='Password'
className='border-2 border-blue-300 focus:border-blue-500'
/>
Size Variants
// Small
<PasswordInput label="Password" size="sm" />
// Medium (default)
<PasswordInput label="Password" size="md" />
// Large
<PasswordInput label="Password" size="lg" />
Best Practices
Security Considerations
- Never store passwords in plain text
- Use HTTPS for all password transmission
- Implement proper password hashing on the server
- Consider rate limiting for password attempts
User Experience
- Provide clear password requirements
- Show real-time validation feedback
- Use consistent error messaging
- Consider password strength indicators
Accessibility
- Always provide descriptive labels
- Use helper text for complex requirements
- Ensure keyboard navigation works
- Test with screen readers
Migration from React Admin
If you're migrating from React Admin's PasswordInput:
// React Admin
<PasswordInput source="password" />
// React SuperAdmin
<PasswordInput label="Password" name="password" />
Key Differences
- Props: Uses
labelinstead ofsource - Styling: Tailwind CSS instead of Material-UI
- Validation: More flexible validation system
- Accessibility: Enhanced ARIA support
Troubleshooting
Common Issues
Toggle button not working
- Ensure the component isn't disabled or readonly
- Check that onClick handlers aren't being blocked Character count not displaying
- Verify
showCharacterCountis set totrue - Ensure
maxLengthis provided Accessibility issues - Check that
labelprop is provided - Verify ARIA attributes are properly set
- Test with keyboard navigation
Performance Considerations
- Debounce validation: For real-time validation, consider debouncing
- Memoization: Use React.memo for complex validation functions
- Bundle size: Component is tree-shakeable and lightweight
Related Components
Input- For text-based inputInput- For text-based inputBooleanInput- For boolean inputSelectInput- For selection from optionsDateInput- For date/time inputNumberInput- For numeric input
API Reference
PasswordInputProps
Extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "size">
interface PasswordInputProps {
// Core props
label?: string;
helperText?: string;
error?: string;
required?: boolean;
size?: 'sm' | 'md' | 'lg';
// State props
loading?: boolean;
disabled?: boolean;
readOnly?: boolean;
// Feature props
leftIcon?: ReactNode;
showCharacterCount?: boolean;
maxLength?: number;
// Validation props
showStrengthIndicator?: boolean;
validateStrength?: (password: string) => StrengthResult;
minLength?: number;
showRequirements?: boolean;
requirements?: PasswordRequirements;
}
PasswordRequirements
interface PasswordRequirements {
minLength?: number;
requireUppercase?: boolean;
requireLowercase?: boolean;
requireNumbers?: boolean;
requireSpecialChars?: boolean;
}
StrengthResult
interface StrengthResult {
score: number;
feedback: string[];
color: 'red' | 'orange' | 'yellow' | 'green';
}