Input

The Input component is one of the most fundamental components in the UI kit. It supports multiple variants, sizes, and states.

Props

InputRoot

PropTypeDefaultDescription
size'sm' | 'base' | 'lg''base'Input size
state'default' | 'error''default'Visual state styling
side'left' | 'center' | 'right'-Text alignment, also used for cursor placement on container click
inputClassNamestring-Additional classes for the inner input
...input propsComponentProps<'input'>-All native input attributes

InputSlot

PropTypeDefaultDescription
side'left' | 'right''left'Which side to place the slot
...div propsComponentProps<'div'>-All native div props

Types

interface InputRootProps extends ComponentProps<"div">, VariantProps<typeof inputVariants> {
  state?: "default" | "error";
  side?: "left" | "right" | "center";
  asChild?: boolean;
  inputClassName?: string;
  size?: "sm" | "base" | "lg";
}

interface InputSlotProps extends ComponentProps<"div"> {
  side?: "left" | "right";
}

Text Alignment

The input component supports different text alignment options:

$
// Left-aligned text (default)
<InputRoot size="sm" placeholder="Left text"/>

// Center-aligned text
<InputRoot size="sm" side="center" placeholder="Center text"/>

// Right-aligned text
<InputRoot size="sm" side="right" placeholder="Right text"/>

// With left prefix (currency example)
<InputRoot size="sm" type="number" placeholder="1.300">
  <InputSlot side="left">$</InputSlot>
</InputRoot>

// With right suffix (icon example)
<InputRoot size="sm" placeholder="Right suffix">
  <InputSlot side="right"><Minus/></InputSlot>
</InputRoot>

States

Inputs can be in different states:

// Error state for validation feedback
<InputRoot size="sm" placeholder="Error" state="error"/>

// Disabled state prevents user interaction
<InputRoot size="sm" placeholder="Disabled" disabled/>

Usage by type

Different input types for various use cases:

$
// Text input (default)
<InputRoot size="sm" placeholder="Text input" />

// Number input with currency prefix
<InputRoot size="sm" type="number" side="right" placeholder="1,234.56">
  <InputSlot>$</InputSlot>
</InputRoot>

// Password input with hidden text
<InputRoot size="sm" type="password" placeholder="Password" />

// Email input with validation
<InputRoot size="sm" type="email" placeholder="name@example.com" />

// Search input with icon
<InputRoot size="sm" type="search" placeholder="Search">
  <InputSlot side="right"><Search/></InputSlot>
</InputRoot>

Interactive Examples

onChange Events

Handle user input with live feedback:

Characters: 0
const [value, setValue] = useState('');
const [count, setCount] = useState(0);

return (
  <InputRoot
    size="sm"
    placeholder="Type something..."
    value={value}
    onChange={(e) => {
      setValue(e.target.value);
      setCount(e.target.value.length);
    }}
  />
);

Number Input with Live Calculation

Number input with real-time calculations:

$
qty
Total: $0.00
const [price, setPrice] = useState('');
const [quantity, setQuantity] = useState('');
const total = (parseFloat(price) || 0) * (parseInt(quantity) || 0);

return (
  <>
    <InputRoot
      size="sm"
      type="number"
      side="right"
      placeholder="0.00"
      value={price}
      onChange={(e) => setPrice(e.target.value)}
    >
      <InputSlot side="left">$</InputSlot>
    </InputRoot>

    <InputRoot
      size="sm"
      type="number"
      placeholder="0"
      value={quantity}
      onChange={(e) => setQuantity(e.target.value)}
    >
      <InputSlot side="right">qty</InputSlot>
    </InputRoot>

    <div>Total: ${total.toFixed(2)}</div>
  </>
);

Form Submission

Complete form example with validation and submission:

$
const [formData, setFormData] = useState({
  name: '', email: '', amount: ''
});
const [errors, setErrors] = useState({});

const handleSubmit = (e) => {
  e.preventDefault();
  const newErrors = {};

  if (!formData.name) newErrors.name = 'Name is required';
  if (!formData.email) newErrors.email = 'Email is required';
  if (!formData.amount) newErrors.amount = 'Amount is required';

  if (Object.keys(newErrors).length > 0) {
    setErrors(newErrors);
    return;
  }

  // Submit form data
  console.log('Form submitted:', formData);
};

return (
  <form onSubmit={handleSubmit}>
    <InputRoot
      size="sm"
      placeholder="Your name"
      value={formData.name}
      state={errors.name ? 'error' : 'default'}
      onChange={(e) => setFormData({...formData, name: e.target.value})}
    />

    <InputRoot
      size="sm"
      type="email"
      placeholder="your.email@example.com"
      value={formData.email}
      state={errors.email ? 'error' : 'default'}
      onChange={(e) => setFormData({...formData, email: e.target.value})}
    />

    <InputRoot
      size="sm"
      type="number"
      side="right"
      placeholder="0.00"
      value={formData.amount}
      state={errors.amount ? 'error' : 'default'}
      onChange={(e) => setFormData({...formData, amount: e.target.value})}
    >
      <InputSlot side="left">$</InputSlot>
    </InputRoot>

    <button type="submit">Submit Form</button>
  </form>
);