Input

A versatile input component for efficiently capturing user information in forms or interfaces.

Example

Tone
Size
Radius
Usage

Features

The Input component provides a highly flexible and accessible way to handle different input types, including text, password, and number fields. It supports additional UI enhancements such as loading indicators, start/end content, and dynamic visibility toggling for passwords.

  • Flexible – Supports multiple input types (text, password, number, etc). Allows adding custom content before (startContent) or after (endContent) the input.

  • Accessible – ARIA attributes like aria-invalid and aria-describedby are included for error handling, ensuring screen readers can convey input state correctly. Labels and descriptions are properly associated with the input.

  • Password Visibility Toggle – Automatically adds a show/hide toggle for password fields with eye icons for better user experience.

  • Loading and Disabled States – Handles isLoading and isDisabled states, visually indicating when an input is inactive or in progress.

  • Error Handling – Displays error messages below the input when provided, with proper IDs for screen reader accessibility.

  • Customizable Styling – Fully styleable via classNames for container, input, labels, and content areas. Supports variants and sizes for different UI needs.

  • Composable Layout – Labels, extra label content, descriptions, and errors are flexibly positioned using a grid layout, ensuring consistent spacing and alignment.

Installation

Install following dependencies:

npm install react-aria-components tw-animate-css tailwindcss-react-aria-components class-variance-authority lucide-react clsx tailwind-merge motion

Add cn helper using clsx and twMerge for conditional class merging in Tailwind components.

lib/utils.ts

Copy and paste the following code into your project.

components/ui/core/input.tsx
npx @libravelui@latest add input

Anatomy

import { Input } from "@/components/ui/core/input";
<Input
  error=""
  description=""
  startContent={null}
  endContent={null}
  label=""
  labelExtra={null}
  classNames={{
    container: "",
    label: "",
    labelExtra: "",
    wrapper: "",
    startContent: "",
    endContent: "",
    input: "",
    description: "",
    error: "",
  }}
  tone=""
  size=""
  isDisabled={false}
  isLoading={false}
  id=""
  name=""
  type=""
  placeholder=""
  className=""
/>

Another Examples

Controlled

A controlled input is managed through state. Its value is determined and updated by external logic, allowing full control over user input and behavior.

Label and Description

You can provide a label and short description below the input to guide the user or explain what kind of data is expected.

Password

When you add type="password", the input automatically becomes a password field with a built-in hide/show toggle for visibility.

Start and End Content

Inputs support decorative or interactive elements positioned before or after the input field. You can provide these elements either:

  1. Directly on the Input component using the startContent and endContent props.

  2. Through the InputGroup wrapper, which allows arbitrary elements to be placed alongside the input using natural layout flow.

Full-size Elements

Use data-fullsize-ele to mark elements that should be full-height and attached to the input edge.

Effects:

  • Matches input height
  • Adjusts input padding automatically
  • Keeps background, border, and focus ring continuous

This is used internally by the password visibility toggle.


With Input

Use inside startContent or endContent.

<Input
  startContent={<span data-fullsize-ele>https://</span>}
  endContent={
    <div data-fullsize-ele>
      <Globe />
    </div>
  }
/>

Input owns the layout and styling.


With InputGroup

Use for custom composition.

<InputGroup tone="default" size="default">
  <span data-fullsize-ele>https://</span>
  <Input />
  <div data-fullsize-ele>
    <Globe />
  </div>
</InputGroup>

InputGroup owns the layout. The inner Input is style-neutral.


Rules

  • data-fullsize-ele is not decorative — only for edge-attached, full-height elements
  • When using InputGroup, apply variants (tone, size, radius) to InputGroup, not to Input
  • Without InputGroup, apply variants directly to Input

Loading

When the input is in a loading state, a spinner or progress indicator is displayed to inform the user that a process is ongoing.

Error

Displays an error message and visual indication (such as a red border) when the input value is invalid or fails validation.

Props

Loading types…