Overview
The Input component provides a fully accessible text input with built-in support for labels, helper text, error messages, and icons. Built on React Aria Components for complete keyboard navigation and form integration.
Import
import { Input } from 'stride-ds';
Basic Usage
import { Input } from 'stride-ds';
function Example() {
return (
<Input
label="Email"
placeholder="Enter your email"
/>
);
}
Variants
Default
Standard input appearance.
<Input
label="Username"
placeholder="Enter username"
/>
Success
Indicate successful validation.
<Input
label="Username"
variant="success"
helperText="Username is available!"
defaultValue="johndoe"
/>
Error
Show validation errors.
<Input
label="Email"
errorMessage="Please enter a valid email address"
defaultValue="invalid-email"
/>
Sizes
Three size options are available:
<Input size="sm" label="Small Input" placeholder="Small" />
<Input size="md" label="Medium Input" placeholder="Medium" />
<Input size="lg" label="Large Input" placeholder="Large" />
With Icons
Left Icon
import { Mail } from 'lucide-react';
<Input
label="Email"
placeholder="Enter your email"
leftIcon={<Mail size={16} />}
/>
Right Icon
import { Eye } from 'lucide-react';
<Input
label="Password"
type="password"
placeholder="Enter password"
rightIcon={<Eye size={16} />}
/>
Password Field Example
import { Lock, Eye, EyeOff } from 'lucide-react';
import { useState } from 'react';
function PasswordInput() {
const [showPassword, setShowPassword] = useState(false);
return (
<Input
label="Password"
type={showPassword ? "text" : "password"}
placeholder="Enter password"
leftIcon={<Lock size={16} />}
rightIcon={
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="cursor-pointer"
>
{showPassword ? <EyeOff size={16} /> : <Eye size={16} />}
</button>
}
/>
);
}
Helper Text
<Input
label="Username"
placeholder="Enter username"
helperText="Must be at least 3 characters long"
/>
Required Fields
<Input
label="Full Name"
placeholder="Enter your full name"
isRequired
helperText="This field is required"
/>
Disabled State
<Input
label="Disabled Input"
placeholder="This input is disabled"
isDisabled
defaultValue="Cannot edit this"
/>
Props
Label text displayed above the input.
Placeholder text shown when the input is empty.
Helper text displayed below the input.
Error message displayed below the input. Automatically sets variant to “error”.
size
'sm' | 'md' | 'lg'
default:"'md'"
Size of the input field.
variant
'default' | 'error' | 'success'
default:"'default'"
Visual variant of the input. Automatically set to “error” when errorMessage is provided.
Icon to display on the left side of the input.
Icon to display on the right side of the input. Can be an interactive element.
Whether the input is required. Shows an asterisk (*) next to the label.
Whether the input is disabled.
HTML input type (text, email, password, number, etc.).
Default value for uncontrolled input.
Value for controlled input.
Handler called when the input value changes.
Additional CSS classes for the wrapper.
Additional CSS classes for the input element.
Accessibility
The Input component provides full accessibility features:
- Keyboard Navigation: Standard text input keyboard navigation
- Focus Management: Clear focus indicators
- Screen Reader Support: Proper labeling and ARIA attributes
- Error Announcements: Error messages are properly announced
- Required Field Indication: Visual and semantic indication of required fields
Best Practices
-
Always provide a
label for accessibility:
<Input label="Email" placeholder="Enter email" />
-
Use
helperText for additional context:
<Input
label="Password"
helperText="Must be at least 8 characters"
/>
-
Show validation feedback with
errorMessage:
<Input
label="Email"
errorMessage="Please enter a valid email"
/>
Examples
import { Input } from 'stride-ds';
import { User, Mail, Lock } from 'lucide-react';
function SignUpForm() {
return (
<div className="space-y-4">
<Input
label="Full Name"
placeholder="Enter your full name"
isRequired
leftIcon={<User size={16} />}
/>
<Input
label="Email"
type="email"
placeholder="Enter your email"
isRequired
leftIcon={<Mail size={16} />}
helperText="We'll never share your email with anyone else"
/>
<Input
label="Password"
type="password"
placeholder="Create a password"
isRequired
leftIcon={<Lock size={16} />}
helperText="Must be at least 8 characters long"
/>
</div>
);
}
All Sizes Comparison
import { User } from 'lucide-react';
<div className="space-y-4">
<Input
label="Small Input"
size="sm"
placeholder="Small size"
leftIcon={<User size={14} />}
/>
<Input
label="Medium Input"
size="md"
placeholder="Medium size"
leftIcon={<User size={16} />}
/>
<Input
label="Large Input"
size="lg"
placeholder="Large size"
leftIcon={<User size={18} />}
/>
</div>
With Validation States
<div className="space-y-4">
<Input
label="Default Input"
placeholder="Default state"
helperText="This is a helper text"
/>
<Input
label="Success Input"
variant="success"
placeholder="Success state"
helperText="Everything looks good!"
defaultValue="valid@example.com"
/>
<Input
label="Error Input"
errorMessage="This field has an error"
placeholder="Error state"
defaultValue="invalid input"
/>
<Input
label="Disabled Input"
isDisabled
placeholder="Disabled state"
defaultValue="Cannot edit"
/>
</div>
The Input component works seamlessly with React Hook Form:
import { useForm } from 'react-hook-form';
import { Input } from 'stride-ds';
function FormExample() {
const { register, handleSubmit, formState: { errors } } = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Input
label="Email"
{...register('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address'
}
})}
errorMessage={errors.email?.message}
/>
</form>
);
}