Input
A flexible text input component with built-in validation, states, and accessibility features.
- Native input validation with custom error messages.
- Supports controlled and uncontrolled modes.
- Polymorphic component rendering via Necto Primitive.
- Focus visible styles for keyboard navigation.
- Automatic aria-invalid handling for validation states.
Usage
The Input component is a flexible, accessible text input with support for various input types and validation states.
Basic Example
import { Input } from '@sprocket-ui/input';
<Input
placeholder="Enter text..."
onChange={(e) => console.log(e.target.value)}
/>Input Types
{/* Text input */}
<Input type="text" placeholder="Username" />
{/* Email input */}
<Input type="email" placeholder="[email protected]" />
{/* Password input */}
<Input type="password" placeholder="Password" />
{/* Number input */}
<Input type="number" placeholder="0" min={0} max={100} />
{/* Search input */}
<Input type="search" placeholder="Search..." />
{/* URL input */}
<Input type="url" placeholder="https://example.com" />
{/* Tel input */}
<Input type="tel" placeholder="+1 (555) 000-0000" />Controlled Input
import { useState } from 'react';
import { Input } from '@sprocket-ui/input';
function ControlledExample() {
const [value, setValue] = useState('');
return (
<Input
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Controlled input"
/>
);
}States
{/* Disabled state */}
<Input isDisabled placeholder="Disabled input" />
{/* Read-only state */}
<Input isReadOnly value="Read-only value" />
{/* Invalid state */}
<Input isInvalid placeholder="Invalid input" />
{/* Required field */}
<Input isRequired placeholder="Required field" />With Validation
import { useState } from 'react';
import { Input } from '@sprocket-ui/input';
function ValidationExample() {
const [email, setEmail] = useState('');
const [isInvalid, setIsInvalid] = useState(false);
const validateEmail = (value: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
setIsInvalid(!emailRegex.test(value) && value.length > 0);
};
return (
<div className="flex flex-col gap-1">
<Input
type="email"
value={email}
onChange={(e) => {
setEmail(e.target.value);
validateEmail(e.target.value);
}}
isInvalid={isInvalid}
placeholder="Enter email"
/>
{isInvalid && (
<span className="text-sm text-red-500">
Please enter a valid email address
</span>
)}
</div>
);
}With Label
import { Input } from '@sprocket-ui/input';
import { Label } from '@sprocket-ui/label';
<div className="flex flex-col gap-2">
<Label htmlFor="username">Username</Label>
<Input id="username" placeholder="Enter username" />
</div>Props
| Name | Type | Default | Description |
|---|---|---|---|
type | UnionType'text' | 'email' | 'password' | 'number' | 'search' | 'url' | 'tel' | 'text' | The type of input to render. |
value | string | — | The current value of the input (controlled mode). |
defaultValue | string | — | The default value of the input (uncontrolled mode). |
placeholder | string | — | Placeholder text shown when the input is empty. |
isDisabled | boolean | false | Whether the input is disabled. |
isReadOnly | boolean | false | Whether the input is read-only. |
isRequired | boolean | false | Whether the input is required. |
isInvalid | boolean | false | Whether the input is in an invalid state. |
className | string | — | Additional CSS classes to apply. |
Events
| Name | Type | Description |
|---|---|---|
onChange | (e: ChangeEvent) → void | Called when the input value changes. |
onFocus | (e: FocusEvent) → void | Called when the input receives focus. |
onBlur | (e: FocusEvent) → void | Called when the input loses focus. |
Accessibility
The Input component follows WAI-ARIA best practices:
- Uses semantic input element for proper form integration
- Automatically sets aria-invalid when isInvalid prop is true
- Automatically sets aria-disabled when isDisabled prop is true
- Automatically sets aria-readonly when isReadOnly prop is true
- Automatically sets aria-required when isRequired prop is true
- Focus management and keyboard navigation work as expected
Styling
The Input component is unstyled by default:
{/* Basic styling */}
<Input
className="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Styled input"
/>
{/* Invalid state styling */}
<Input
isInvalid
className="px-4 py-2 border border-red-500 rounded-lg focus:ring-2 focus:ring-red-500"
placeholder="Invalid input"
/>
{/* Disabled styling */}
<Input
isDisabled
className="px-4 py-2 border border-gray-200 rounded-lg bg-gray-100 text-gray-400 cursor-not-allowed"
placeholder="Disabled input"
/>