Input
The Input component allows users to enter text data in forms and interfaces. It provides a flexible and accessible way to collect user input with built-in support for validation, labels, icons, and various visual styles.
Import
import { Input } from '@flexi-ui/input'Usage
Basic
A simple input field with a label and placeholder text.
With Description
Add helper text below the input to provide additional context or instructions.
Required
Mark an input as required with the isRequired prop. This adds a visual indicator and proper ARIA attributes.
Input Types
The Input component supports all standard HTML5 input types for different data formats.
All Input Types
Variants
Choose from four visual variants to match your design system.
Flat (Default)
The flat variant has a subtle background with no border.
Bordered
The bordered variant has a visible border around the input.
Faded
The faded variant has a semi-transparent background with a border.
Underlined
The underlined variant has only a bottom border.
All Variants
Compare all variants side by side.
Sizes
The Input component comes in three sizes: small, medium, and large.
Small
Medium (Default)
Large
All Sizes
Compare all sizes side by side.
Colors
Apply different color themes to inputs for various contexts.
Default
Primary
Secondary
Success
Warning
Error
All Colors
Compare all color variants side by side.
With Start and End Content
Add icons or other content at the start or end of the input field.
Start Content
End Content
Both Start and End Content
Multiple Icons
States
Disabled
Disable user interaction with the isDisabled prop.
Read-Only
Make an input read-only with the isReadOnly prop.
Required
Mark fields as required with the isRequired prop.
All States
Compare all states side by side.
Validation
Invalid State
Use the isInvalid prop to mark an input as invalid and display an error message.
Email Validation
Real-time email validation example.
Password Strength Validation
Password validation with strength indicator.
Form Validation
Complete form validation example.
Password Toggle
Create a password input with a toggle to show/hide the password.
Basic Password Toggle
Password Toggle with Validation
Controlled vs Uncontrolled
Controlled Input
The input value is controlled by React state.
Uncontrolled Input
The input manages its own state internally.
Controlled with Multiple Inputs
Custom Styling
Custom Classes
Use the classNames prop to customize specific parts of the input.
Custom Radius
Customize the border radius for different styles.
Styled with Tailwind
Advanced styling with Tailwind CSS.
Real-World Examples
Login Form
A complete login form with email and password inputs.
Search Bar
A search input with autocomplete suggestions.
Profile Editor
A complete profile editing form.
API Reference
Input Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | - | Label text displayed above the input |
placeholder | string | - | Placeholder text shown when input is empty |
description | string | - | Helper text displayed below the input |
errorMessage | string | ReactNode | - | Error message to display when input is invalid |
value | string | - | Controlled value of the input |
defaultValue | string | - | Default value for uncontrolled input |
type | string | 'text' | HTML input type (text, email, password, number, url, tel, search, etc.) |
name | string | - | Name attribute for form submission |
size | 'sm' | 'md' | 'lg' | 'md' | Size of the input field |
radius | 'none' | 'sm' | 'md' | 'lg' | 'full' | 'md' | Border radius of the input |
variant | 'flat' | 'bordered' | 'faded' | 'underlined' | 'flat' | Visual style variant |
color | 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'default' | Color theme for the input |
isRequired | boolean | false | Whether the input is required |
isReadOnly | boolean | false | Whether the input is read-only |
isDisabled | boolean | false | Whether the input is disabled |
isInvalid | boolean | false | Whether the input is in an invalid state |
startContent | ReactNode | - | Content to display at the start of the input (e.g., icons) |
endContent | ReactNode | - | Content to display at the end of the input (e.g., icons, buttons) |
classNames | InputClassNames | - | Custom classes for different slots |
className | string | - | Additional CSS class for the base element |
autoFocus | boolean | false | Whether to auto-focus the input on mount |
autoComplete | string | - | HTML autocomplete attribute |
min | number | string | - | Minimum value (for number/date inputs) |
max | number | string | - | Maximum value (for number/date inputs) |
minLength | number | - | Minimum length of input value |
maxLength | number | - | Maximum length of input value |
pattern | string | - | Regex pattern for validation |
onChange | (e: ChangeEvent<HTMLInputElement>) => void | - | Change event handler |
onFocus | (e: FocusEvent<HTMLInputElement>) => void | - | Focus event handler |
onBlur | (e: FocusEvent<HTMLInputElement>) => void | - | Blur event handler |
onKeyDown | (e: KeyboardEvent<HTMLInputElement>) => void | - | Key down event handler |
onKeyUp | (e: KeyboardEvent<HTMLInputElement>) => void | - | Key up event handler |
InputClassNames
Object for customizing component slots:
type InputClassNames = {
base?: string // Main wrapper element
label?: string // Label element
inputWrapper?: string // Input wrapper (contains input and icons)
input?: string // Input element
description?: string // Description text element
errorMessage?: string // Error message element
}Slots
The Input component has the following slots that can be styled:
- base - The main wrapper containing all elements
- label - The label element displayed above the input
- inputWrapper - The wrapper containing the input and start/end content
- input - The actual input element
- description - The description text displayed below the input
- errorMessage - The error message text displayed when invalid
Accessibility
The Input component follows WAI-ARIA best practices for form inputs:
Keyboard Navigation
- Tab - Move focus to/from the input
- Shift + Tab - Move focus backwards
- All standard input shortcuts - Copy (Ctrl+C), Paste (Ctrl+V), Select All (Ctrl+A), etc.
Screen Reader Support
- Labels are automatically associated with inputs using proper
htmlForandidattributes - Required fields are announced with
aria-required="true" - Invalid fields are announced with
aria-invalid="true" - Error messages are linked using
aria-describedby - Disabled state is communicated with
aria-disabled="true" - Description text is associated using
aria-describedby
ARIA Attributes
The component automatically manages these ARIA attributes:
aria-label- When no visible label is providedaria-labelledby- Associates the input with its labelaria-describedby- Links description and error messagesaria-required- Indicates required fieldsaria-invalid- Indicates validation statearia-disabled- Indicates disabled state
Focus Management
- Clear focus indicators for keyboard navigation
- Focus is properly managed when using
autoFocus - Focus states are visible and meet WCAG contrast requirements
Best Practices
- Always provide labels - Use the
labelprop oraria-labelfor screen readers - Use appropriate input types - Helps with mobile keyboards and browser validation
- Provide clear error messages - Be specific about what went wrong and how to fix it
- Mark required fields - Use
isRequiredto indicate mandatory fields - Use descriptions for additional context - Help users understand what's expected
- Ensure sufficient color contrast - Don't rely solely on color to convey state
Best Practices
1. Use Appropriate Input Types
Choose the correct input type for the data you're collecting to provide better user experience and mobile keyboard optimization:
<Input type="email" label="Email" /> // Shows @ on mobile keyboards
<Input type="tel" label="Phone" /> // Shows numeric keypad
<Input type="url" label="Website" /> // Shows .com on mobile keyboards
<Input type="number" label="Age" /> // Shows number pad2. Provide Clear Labels and Descriptions
Always include descriptive labels and use descriptions to provide additional context:
<Input
label="Password"
description="Must be at least 8 characters with mixed case and numbers"
type="password"
/>3. Implement Real-Time Validation
Validate user input as they type to provide immediate feedback:
const [email, setEmail] = useState('')
const isInvalid = email !== '' && !email.includes('@')
<Input
value={email}
onChange={(e) => setEmail(e.target.value)}
isInvalid={isInvalid}
errorMessage={isInvalid && "Please enter a valid email"}
/>4. Use Icons for Visual Clarity
Add icons to help users quickly identify the purpose of each field:
<Input
label="Email"
startContent={<Mail className="w-4 h-4 text-gray-400" />}
/>5. Handle Loading and Disabled States
Disable inputs during form submission or loading states:
<Input
label="Username"
isDisabled={isSubmitting}
description={isSubmitting ? "Saving..." : undefined}
/>6. Group Related Inputs
Use consistent sizing and styling for related form fields:
<div className="space-y-4">
<Input size="md" label="First Name" />
<Input size="md" label="Last Name" />
<Input size="md" label="Email" type="email" />
</div>7. Implement Proper Error Handling
Show specific, actionable error messages:
// ❌ Bad
<Input isInvalid errorMessage="Invalid input" />
// ✅ Good
<Input
isInvalid
errorMessage="Email must include @ symbol and domain name"
/>8. Use Autocomplete Attributes
Help browsers autofill forms correctly:
<Input label="Email" type="email" autoComplete="email" />
<Input label="Password" type="password" autoComplete="current-password" />
<Input label="New Password" type="password" autoComplete="new-password" />9. Consider Mobile UX
Ensure inputs are properly sized for touch targets (minimum 44x44px):
<Input size="lg" label="Mobile-Friendly Input" />10. Provide Visual Feedback
Use colors and states to communicate the input status:
<Input
color={isValid ? "success" : "default"}
label="Username"
description={isValid ? "Username available!" : "Enter a username"}
/>Troubleshooting
Input value not updating
Problem: The input value doesn't change when typing.
Solution: Make sure you're using either controlled (with value and onChange) or uncontrolled (with defaultValue) pattern correctly:
// ✅ Controlled
const [value, setValue] = useState('')
<Input value={value} onChange={(e) => setValue(e.target.value)} />
// ✅ Uncontrolled
<Input defaultValue="initial value" />
// ❌ Don't mix them
<Input value={value} defaultValue="initial" />Icons not displaying properly
Problem: Icons from startContent or endContent are misaligned or too large.
Solution: Ensure icons have proper sizing classes and use flexbox:
// ✅ Good
<Input
startContent={<Mail className="w-4 h-4 text-gray-400" />}
/>
// ❌ Bad - no sizing
<Input
startContent={<Mail />}
/>Validation not working
Problem: Error messages don't appear or validation doesn't trigger.
Solution: Make sure to set both isInvalid and errorMessage props:
// ✅ Good
<Input
isInvalid={hasError}
errorMessage={hasError && "This field is required"}
/>
// ❌ Bad - missing isInvalid
<Input errorMessage="Error" />AutoFocus not working
Problem: Input doesn't receive focus on page load.
Solution: Ensure autoFocus prop is set and there's only one autofocused element per page:
<Input label="Username" autoFocus />Style overrides not applying
Problem: Custom styles via classNames prop aren't being applied.
Solution: Check that you're targeting the correct slot and using proper Tailwind classes:
// ✅ Correct slot targeting
<Input
classNames={{
input: 'text-blue-600',
inputWrapper: 'border-2 border-blue-500',
}}
/>
// ❌ Wrong approach
<Input className="text-blue-600" /> // Only styles base wrapperPassword toggle button not working
Problem: Clicking the eye icon doesn't toggle password visibility.
Solution: Ensure you're preventing default button behavior and managing state correctly:
const [isVisible, setIsVisible] = useState(false)
<Input
type={isVisible ? 'text' : 'password'}
endContent={
<button
type="button" // Important: prevents form submission
onClick={() => setIsVisible(!isVisible)}
>
{isVisible ? <EyeOff /> : <Eye />}
</button>
}
/>Form submission issues
Problem: Form submits even when inputs are invalid.
Solution: Implement proper form validation before submission:
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
// Validate all fields first
if (hasErrors) {
return
}
// Then submit
submitForm()
}Number input accepts non-numeric characters
Problem: Users can type non-numeric characters in number inputs.
Solution: Use type="number" and optionally add additional validation:
<Input
type="number"
min={0}
max={100}
onChange={(e) => {
const value = e.target.value
if (value === '' || /^\d+$/.test(value)) {
setValue(value)
}
}}
/>Related Components
On this page
- Import
- Usage
- Basic
- With Description
- Required
- Input Types
- All Input Types
- Variants
- Flat (Default)
- Bordered
- Faded
- Underlined
- All Variants
- Sizes
- Small
- Medium (Default)
- Large
- All Sizes
- Colors
- Default
- Primary
- Secondary
- Success
- Warning
- Error
- All Colors
- With Start and End Content
- Start Content
- End Content
- Both Start and End Content
- Multiple Icons
- States
- Disabled
- Read-Only
- Required
- All States
- Validation
- Invalid State
- Email Validation
- Password Strength Validation
- Form Validation
- Password Toggle
- Basic Password Toggle
- Password Toggle with Validation
- Controlled vs Uncontrolled
- Controlled Input
- Uncontrolled Input
- Controlled with Multiple Inputs
- Custom Styling
- Custom Classes
- Custom Radius
- Styled with Tailwind
- Real-World Examples
- Login Form
- Search Bar
- Profile Editor
- API Reference
- Input Props
- InputClassNames
- Slots
- Accessibility
- Keyboard Navigation
- Screen Reader Support
- ARIA Attributes
- Focus Management
- Best Practices
- Best Practices
- 1. Use Appropriate Input Types
- 2. Provide Clear Labels and Descriptions
- 3. Implement Real-Time Validation
- 4. Use Icons for Visual Clarity
- 5. Handle Loading and Disabled States
- 6. Group Related Inputs
- 7. Implement Proper Error Handling
- 8. Use Autocomplete Attributes
- 9. Consider Mobile UX
- 10. Provide Visual Feedback
- Troubleshooting
- Input value not updating
- Icons not displaying properly
- Validation not working
- AutoFocus not working
- Style overrides not applying
- Password toggle button not working
- Form submission issues
- Number input accepts non-numeric characters
- Related Components