Skip to content
Lenso UI

Input

Migration guide for Input from HeroUI v2 to v3

Refer to the v3 Input documentation 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:

import { Input } from "@lenso/ui";
export default function App() {  return (    <Input      label="Email"      placeholder="Enter your email"      type="email"    />  );}

In v3, Input is a primitive component. For form fields with labels and validation, use TextField which wraps Input with Label, Description, and FieldError:

import { TextField, Label, Input, FieldError } from "@lenso/ui";
export default function App() {  return (    <TextField name="email" type="email">      <Label>Email</Label>      <Input placeholder="Enter your email" />      <FieldError />    </TextField>  );}

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 Propv3 LocationNotes
labelLabelUse Label component inside TextField
descriptionDescriptionUse Description component inside TextField
errorMessageFieldErrorUse FieldError component inside TextField
variantInputChanged 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)
fullWidthInput or TextFieldStill supported on both Input and TextField (fullWidth boolean prop)
labelPlacement-Use layout with Label
startContentInputGroup.PrefixUse InputGroup with InputGroup.Prefix inside TextField
endContentInputGroup.SuffixUse InputGroup with InputGroup.Suffix inside TextField
isClearable-Implement manually with button
isRequired, isInvalidTextFieldUse on TextField
validateTextFieldUse validate on TextField
classNames-Use className on individual components
onValueChangeInputUse onChange event handler

Migration Examples

Form Validation

{/* With description */}<Input  description="We'll never share your email"  label="Email"  type="email"/>
{/* With error message */}<Input  errorMessage="Please enter a valid email"  isInvalid  label="Email"  type="email"/>
{/* Required */}<Input isRequired label="Email" type="email" />

Input with Start/End Content

For inputs with prefix or suffix content, use the InputGroup compound component:

<Input  label="Price"  startContent={<span>$</span>}  type="number"/>

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

<Input  isClearable  label="Email"  onClear={() => console.log("cleared")}  type="email"/>

Controlled Input

import { useState } from "react";
const [value, setValue] = useState("");
<Input  label="Email"  onValueChange={setValue}  type="email"  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
  13. onValueChange Removed: Use onChange event handler
  14. ClassNames Removed: Use className props on individual components