Skip to main content

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 present
  • aria-describedby: Links to helper text and error messages
  • aria-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​

  1. Never store passwords in plain text
  2. Use HTTPS for all password transmission
  3. Implement proper password hashing on the server
  4. Consider rate limiting for password attempts

User Experience​

  1. Provide clear password requirements
  2. Show real-time validation feedback
  3. Use consistent error messaging
  4. Consider password strength indicators

Accessibility​

  1. Always provide descriptive labels
  2. Use helper text for complex requirements
  3. Ensure keyboard navigation works
  4. 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 label instead of source
  • 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 showCharacterCount is set to true
  • Ensure maxLength is provided Accessibility issues
  • Check that label prop 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

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';
}