Skip to main content

Primitive single-line text input component that accepts standard HTML attributes.

Import

import { Input } from "heroui-solid";

For validation, labels, and error messages, see TextField.

Usage

import { Input } from "heroui-solid"

export function Basic() {
  return <Input aria-label="Name" class="w-64" placeholder="Enter your name" />
}

Input Types

import { Input, Label } from "heroui-solid"

export function Types() {
  return (
    <div class="flex w-80 flex-col gap-4">
      <div class="flex flex-col gap-1">
        <Label for="input-type-email">Email</Label>
        <Input
          id="input-type-email"
          placeholder="jane@example.com"
          type="email"
        />
      </div>
      <div class="flex flex-col gap-1">
        <Label for="input-type-number">Age</Label>
        <Input id="input-type-number" min={0} placeholder="30" type="number" />
      </div>
      <div class="flex flex-col gap-1">
        <Label for="input-type-password">Password</Label>
        <Input
          id="input-type-password"
          placeholder="••••••••"
          type="password"
        />
      </div>
    </div>
  )
}

Controlled

Standalone inputs are controlled with Solid's native onInput event (HeroUI React uses React's onChange, which fires per keystroke — Solid's onChange fires on blur).

https://heroui.com
import { Input } from "heroui-solid"
import { createSignal } from "solid-js"

export function Controlled() {
  const [value, setValue] = createSignal("heroui.com")

  return (
    <div class="flex w-80 flex-col gap-2">
      <Input
        aria-label="Domain"
        placeholder="domain"
        value={value()}
        onInput={(event) => setValue(event.currentTarget.value)}
      />
      <span class="px-1 text-sm text-muted">
        https://{value() || "your-domain"}
      </span>
    </div>
  )
}

Full Width

import { Input } from "heroui-solid"

export function FullWidth() {
  return (
    <div class="w-[400px] space-y-3">
      <Input fullWidth placeholder="Full width input" />
    </div>
  )
}

Variants

The Input component supports two visual variants:

  • primary (default) - Standard styling with shadow, suitable for most use cases
  • secondary - Lower emphasis variant without shadow, suitable for use in Surface components
import { Input } from "heroui-solid"

export function Variants() {
  return (
    <div class="flex w-[240px] flex-col gap-2">
      <Input fullWidth placeholder="Primary input" variant="primary" />
      <Input fullWidth placeholder="Secondary input" variant="secondary" />
    </div>
  )
}

In Surface

When used inside a Surface component, use variant="secondary" to apply the lower emphasis variant suitable for surface backgrounds.

import { Input, Surface } from "heroui-solid"

export function OnSurface() {
  return (
    <Surface class="flex h-[180px] w-[280px] items-center justify-center rounded-3xl bg-surface p-4">
      <Input class="w-full" placeholder="Your name" variant="secondary" />
    </Surface>
  )
}
  • TextField: Composition-friendly fields with labels and validation
  • TextArea: Multiline text input
  • Label: Accessible label for form controls

Styling

Passing Tailwind CSS classes

import { Input, Label } from "heroui-solid";

function CustomInput() {
  return (
    <div class="flex flex-col gap-2">
      <Label htmlFor="custom-input">Project name</Label>
      <Input
        id="custom-input"
        class="rounded-xl border border-border/70 bg-surface-secondary px-4 py-2 text-sm shadow-sm focus-visible:border-accent"
        placeholder="New web app"
      />
    </div>
  );
}

Customizing the component classes

The base class .input powers every instance. Override it once with @layer components.

@layer components {
  .input {
    @apply rounded-lg border border-border px-4 py-2 text-sm shadow-sm transition-colors;

    &:hover {
      @apply bg-surface-secondary border-border/80;
    }

    &:focus-visible {
      @apply border-accent ring-2 ring-accent/20;
    }

    &[data-invalid] {
      @apply border-danger text-danger;
    }
  }
}

CSS Classes

  • .input – Native input element styling
  • .input--primary / .input--secondary – Visual variants
  • .input--full-width – Full width modifier

Interactive States

  • Hover: :hover
  • Focus: :focus
  • Invalid: [data-invalid] (stamped by the enclosing TextField; also syncs with aria-invalid)
  • Disabled: :disabled

API Reference

Input Props

Input accepts all standard HTML <input> attributes plus the following:

PropTypeDefaultDescription
classstring-Tailwind classes merged with the component styles.
fullWidthbooleanfalseWhether the input should take full width of its container
variant"primary" | "secondary""primary"Visual variant of the component. primary is the default style with shadow. secondary is a lower emphasis variant without shadow, suitable for use in surfaces.

For validation props like isInvalid and isRequired, use TextField with Input as a child component.

Differences from HeroUI React

  • Use class instead of className and for instead of htmlFor on labels.
  • Control standalone inputs with onInput (per keystroke); Solid's onChange fires on blur. Inside a TextField, use the field's onChange(value) instead.
  • Inside a TextField the input is wired through Kobalte, which stamps data-invalid as an attribute (no ="true" value) — both selector forms are styled.

Last updated: 7/19/26, 3:27 AM

HeroUI SolidUnofficial SolidJS port of HeroUI v3, built on Kobalte and @heroui/styles