Installation
Terminal
TSXReactTailwind
npx @uiblox/cli add inputVisual Variations
Toggle between three different visual styles: default (bordered), filled (background), and underline (minimal).
Standard text input
Input with search icon
Non-editable state
Basic Usage
Copy & paste ready
import { Input } from "@/components/ui";
<Input placeholder="Enter text..." />Input Types
Copy & paste ready
<Input type="text" placeholder="Text input" />
<Input type="email" placeholder="Email input" />
<Input type="password" placeholder="Password input" />
<Input type="number" placeholder="Number input" />
<Input type="search" placeholder="Search..." />Disabled State
Copy & paste ready
<Input disabled placeholder="Disabled input" />
<Input disabled value="Disabled with value" />With Label
Copy & paste ready
<div className="space-y-2">
<label htmlFor="email" className="text-sm font-medium text-gray-700">
Email
</label>
<Input id="email" type="email" placeholder="you@example.com" />
</div>With Button
Copy & paste ready
<div className="flex gap-2">
<Input placeholder="Search..." className="flex-1" />
<Button>Search</Button>
</div>File Input
Copy & paste ready
<Input type="file" />Accessibility
Form inputs are critical for accessibility. Every input must be properly labeled and error states must be clearly communicated.
Keyboard Support
Tab- Move focus to inputShift+Tab- Move focus away- Standard text editing keys supported
Required Attributes
- ✓Always include
idand matching<label> - ✓Use
aria-describedbyfor helper text - ✓Use
aria-invalidfor error states
Accessible Input Patterns
// Always use labels - never rely on placeholder alone
<div className="space-y-2">
<label htmlFor="email" className="text-sm font-medium text-white">
Email address
<span className="text-red-400" aria-hidden="true">*</span>
<span className="sr-only">(required)</span>
</label>
<Input
id="email"
type="email"
required
aria-required="true"
placeholder="you@example.com"
aria-describedby="email-hint"
/>
<p id="email-hint" className="text-sm text-[#94a3b8]">
We'll never share your email with anyone.
</p>
</div>
// Error state with proper announcements
<div className="space-y-2">
<label htmlFor="password" className="text-sm font-medium text-white">
Password
</label>
<Input
id="password"
type="password"
aria-invalid="true"
aria-describedby="password-error"
className="border-red-500"
/>
<p id="password-error" className="text-sm text-red-400" role="alert">
Password must be at least 8 characters
</p>
</div>
// Search input with role
<div className="relative" role="search">
<label htmlFor="search" className="sr-only">
Search products
</label>
<Input
id="search"
type="search"
placeholder="Search products..."
aria-label="Search products"
/>
</div>
// Disabled input with explanation
<div className="space-y-2">
<label htmlFor="readonly" className="text-sm font-medium text-[#94a3b8]">
Account ID(read-only)
</label>
<Input
id="readonly"
value="ACC-12345"
disabled
aria-disabled="true"
aria-describedby="readonly-hint"
/>
<p id="readonly-hint" className="text-sm text-[#64748b]">
This field cannot be edited
</p>
</div>Best Practices
- • Never use placeholder as the only label
- • Associate error messages with
aria-describedby - • Use
role="alert"for dynamic error messages - • Mark required fields with both visual indicator and
aria-required - • Provide clear instructions for expected input format
Props
Input accepts all standard HTML input attributes plus:
| Prop | Type | Default | Description |
|---|---|---|---|
| type | string | "text" | The input type (text, email, password, number, etc.) |
| placeholder | string | - | Placeholder text |
| disabled | boolean | false | Whether the input is disabled |
| className | string | - | Additional CSS classes |
Source Code
Copy this code into src/components/ui/input.tsx:
input.tsx
TSXReactTailwind
import * as React from "react";
import { cn } from "@/lib/utils";
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 ring-offset-background",
"file:border-0 file:bg-transparent file:text-sm file:font-medium",
"placeholder:text-gray-500 dark:placeholder:text-gray-400",
"focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2",
"disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
}
);
Input.displayName = "Input";
export { Input };