# Input
**Category**: react
**URL**: https://www.heroui.com/docs/react/migration/input
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/migration/(components)/input.mdx
> Migration guide for Input from HeroUI v2 to v3
***
Refer to the [v3 Input documentation](/docs/react/components/input) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
## Key Change: Input → TextField
**v2:** `Input` was a full-featured component with built-in label, description, error messages, validation, variants, colors, sizes, etc.
**v3:** `Input` is now a primitive component (just the input element). For form fields, use `TextField` which wraps `Input` with `Label`, `Description`, and `FieldError` components. In v2 there was no separate TextField or InputGroup; the single Input component handled labels, descriptions, start/end content, and validation.
## When to Use Input vs TextField
### Use TextField (Most Cases)
Use `TextField` when you need:
- Labels
- Descriptions
- Error messages
- Validation
- Form integration
### Use Input (Primitive Only)
Use `Input` when you need:
- Just a basic input element
- Custom label/error handling
- Integration with custom form components
## Structure Changes
In v2, `Input` was a full-featured component that accepted props for label, description, placeholder, and other elements:
```tsx
import { Input } from "@heroui/react";
export default function App() {
return (
);
}
```
In v3, `Input` is a primitive component. For form fields with labels and validation, use `TextField` which wraps `Input` with `Label`, `Description`, and `FieldError`:
```tsx
import { TextField, Label, Input, FieldError } from "@heroui/react";
export default function App() {
return (
);
}
```
## Key Changes
### 1. Component Split
**v2:** Single `Input` component with all features
**v3:** Split into `Input` (primitive) and `TextField` (compound component)
### 2. Prop Changes
| v2 Prop | v3 Location | Notes |
|---------|-------------|-------|
| `label` | `Label` | Use `Label` component inside `TextField` |
| `description` | `Description` | Use `Description` component inside `TextField` |
| `errorMessage` | `FieldError` | Use `FieldError` component inside `TextField` |
| `variant` | `Input` | Changed from multiple variants (flat, bordered, underlined, faded) to `"primary"` (default, with shadow) and `"secondary"` (lower emphasis, no shadow, for surfaces) |
| `color`, `size`, `radius` | - | Removed (use Tailwind CSS) |
| `fullWidth` | `Input` or `TextField` | Still supported on both `Input` and `TextField` (`fullWidth` boolean prop) |
| `labelPlacement` | - | Use layout with `Label` |
| `startContent` | `InputGroup.Prefix` | Use `InputGroup` with `InputGroup.Prefix` inside `TextField` |
| `endContent` | `InputGroup.Suffix` | Use `InputGroup` with `InputGroup.Suffix` inside `TextField` |
| `isClearable` | - | Implement manually with button |
| `isRequired`, `isInvalid` | `TextField` | Use on `TextField` |
| `validate` | `TextField` | Use `validate` on `TextField` |
| `classNames` | - | Use `className` on individual components |
| `onValueChange` | `Input` | Use `onChange` event handler |
## Migration Examples
### Form Validation
```tsx
{/* With description */}
{/* With error message */}
{/* Required */}
```
```tsx
import { Description } from "@heroui/react";
{/* With description */}
We'll never share your email
{/* With error message */}
{
if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value)) {
return "Please enter a valid email";
}
return null;
}}
>
{/* Required */}
```
### Input with Start/End Content
For inputs with prefix or suffix content, use the **InputGroup** compound component:
```tsx
$}
type="number"
/>
```
```tsx
import { InputGroup } from "@heroui/react";
$
```
**InputGroup** provides proper styling and layout for prefix/suffix content. Use:
- `InputGroup.Prefix` for content before the input (replaces `startContent`)
- `InputGroup.Suffix` for content after the input (replaces `endContent`)
- `InputGroup.Input` for the input element itself
### Input with Clear Button
```tsx
console.log("cleared")}
type="email"
/>
```
```tsx
import { useState } from "react";
import { CloseButton } from "@heroui/react";
const [value, setValue] = useState("");
```
### Controlled Input
```tsx
import { useState } from "react";
const [value, setValue] = useState("");
```
```tsx
import { useState } from "react";
const [value, setValue] = useState("");
setValue(e.target.value)}
value={value}
/>
```
## Summary
1. **Component Split**: `Input` → `TextField` for form fields, `Input` for primitive input
2. **Label Required**: Must use `Label` component instead of `label` prop
3. **Error Display**: Must use `FieldError` component instead of `errorMessage` prop
4. **Description**: Must use `Description` component instead of `description` prop
5. **Validation**: Move `validate` function from `Input` to `TextField`
6. **Start/End Content**: Use `InputGroup` with `InputGroup.Prefix`/`InputGroup.Suffix` inside `TextField`
7. **Clear Button**: Implement manually with `CloseButton`
8. **Variants Simplified**: v2 had multiple variants (flat, bordered, underlined, faded); v3 has `"primary"` (default) and `"secondary"` (for surfaces)
9. **Full Width**: `fullWidth` prop is still available on both `Input` and `TextField`
10. **Colors Removed**: Use Tailwind CSS classes
11. **Sizes Removed**: Use Tailwind CSS classes
12. **Radius Removed**: Use Tailwind CSS classes
12. **onValueChange Removed**: Use `onChange` event handler
13. **ClassNames Removed**: Use `className` props on individual components