A foundational input component that provides consistent styling across form fields while remaining highly customizable.
Installation
The Input component uses:
- Custom utility functions from
@/lib/utils
- Native HTML input element as base
Basic Usage
import { Input } from "@/components/ui/input";
export default function Example() {
return <Input placeholder="Enter your email" />;
}
Email
Password
Text
Number
File
Email input with browser validation. <Input
type="password"
placeholder="••••••••"
/>
Password input with masked characters.<Input
type="text"
placeholder="Enter text"
/>
Standard text input (default).<Input
type="number"
placeholder="0"
min="0"
max="100"
/>
Numeric input with browser controls.<Input
type="file"
accept=".pdf,.doc,.docx"
/>
File upload input with styled file button.
Real-World Examples
From modules/auth/components/LoginForm.tsx:54-62:
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useState } from "react";
export function LoginForm() {
const [email, setEmail] = useState("");
return (
<div className="space-y-2">
<Label htmlFor="email">Correo electrónico</Label>
<Input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="[email protected]"
className="py-6"
required
/>
</div>
);
}
From modules/auth/components/LoginForm.tsx:68-76:
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { EyeIcon, EyeOffIcon } from "lucide-react";
import { useState } from "react";
export function PasswordField() {
const [password, setPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
return (
<div className="relative">
<Input
id="password"
type={showPassword ? "text" : "password"}
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
className="py-6"
required
/>
<Button
type="button"
variant="ghost"
size="sm"
className="absolute right-2 top-1/2 -translate-y-1/2"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? <EyeOffIcon className="h-4 w-4" /> : <EyeIcon className="h-4 w-4" />}
</Button>
</div>
);
}
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
<div className="space-y-2">
<Label htmlFor="username">Username</Label>
<Input id="username" placeholder="johndoe" />
</div>
Props
HTML input typeCommon options: text | email | password | number | tel | url | search | date | file
Placeholder text displayed when input is empty
Change event handler: (e: React.ChangeEvent<HTMLInputElement>) => void
Additional CSS classes to apply to the input
Disables the input and applies disabled styles (cursor-not-allowed, 50% opacity)
Makes the input required for form submission
Indicates input validation state for screen readers
HTML id attribute, used to associate with Label component
Accessibility
- Fully extends native HTML input attributes
- Supports
disabled state with appropriate cursor and opacity
- Placeholder text uses
text-muted-foreground for sufficient contrast
- Works seamlessly with Label component using
id and htmlFor
- Use
aria-invalid and aria-describedby for validation feedback
- Required inputs should be marked with
required attribute
Styling Details
- Width:
w-full (100% of container)
- Background: Transparent by default
- Text size: Base (16px) on mobile, small (14px) on desktop (md breakpoint)
- File input: Styled file button with transparent background
- Placeholder: Uses muted foreground color
- Disabled state:
cursor-not-allowed with 50% opacity
Customization
The Input component accepts any custom classes through the className prop:
<Input
className="py-6 text-lg border-2 border-blue-500"
placeholder="Custom styled input"
/>
TypeScript
type InputProps = React.ComponentProps<"input">;
The component extends all native HTML input attributes without additional custom props (except className merging via cn).