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