# 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("");
setValue(e.target.value)} /> {value && ( setValue("")} /> )}
```
### 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