Input
Primitive single-line text input component that accepts standard HTML attributes
Usage
import { Input } from '@lenso/ui';"use client";
import { Input } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";
// HeroUI v3.2.6, e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e, Apache-2.0.const styles = stylex.create({ field: { width: 256 } });export function Basic() { return <Input aria-label="Name" xstyle={styles.field} placeholder="Enter your name" />;}Local adaptation source above. Derived from HeroUI v3.2.6 source.
For validation, labels, and error messages, see TextField.
Examples
Variants
The Input component supports two visual variants:
primary(default) - Standard styling with shadow, suitable for most use casessecondary- Lower emphasis variant without shadow, suitable for use in Surface components
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ root: { display: "flex", width: 240, flexDirection: "column", gap: 8 },});export function Variants() { return ( <div {...stylex.props(styles.root)}> <Input fullWidth placeholder="Primary input" variant="primary" /> <Input fullWidth placeholder="Secondary input" variant="secondary" /> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
In Surface
When used inside a Surface component, use variant="secondary" to apply the lower emphasis variant suitable for surface backgrounds.
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input, Surface } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ root: { display: "flex", height: 180, width: 280, alignItems: "center", justifyContent: "center", borderRadius: 24, backgroundColor: "var(--surface)", padding: 16, },});export function OnSurface() { return ( <Surface xstyle={styles.root}> <Input fullWidth placeholder="Your name" variant="secondary" /> </Surface> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Full Width
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ root: { width: 400 } });export function FullWidth() { return ( <div {...stylex.props(styles.root)}> <Input fullWidth placeholder="Full width input" /> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Input Types
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input, Label } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ root: { display: "flex", width: 320, flexDirection: "column", gap: 16 }, field: { display: "flex", flexDirection: "column", gap: 4 },});export function Types() { return ( <div {...stylex.props(styles.root)}> <div {...stylex.props(styles.field)}> <Label htmlFor="input-type-email">Email</Label> <Input id="input-type-email" placeholder="[email protected]" type="email" /> </div> <div {...stylex.props(styles.field)}> <Label htmlFor="input-type-number">Age</Label> <Input id="input-type-number" min={0} placeholder="30" type="number" /> </div> <div {...stylex.props(styles.field)}> <Label htmlFor="input-type-password">Password</Label> <Input id="input-type-password" placeholder="••••••••" type="password" /> </div> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Controlled
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input } from "@lenso/ui";import * as React from "react";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ root: { display: "flex", width: 320, flexDirection: "column", gap: 8 }, value: { paddingInline: 4, fontSize: 14, color: "var(--muted)" },});export function Controlled() { const [value, setValue] = React.useState("heroui.com"); return ( <div {...stylex.props(styles.root)}> <Input aria-label="Domain" placeholder="domain" value={value} onValueChange={setValue} /> <span {...stylex.props(styles.value)}>https://{value || "your-domain"}</span> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Customization
Tailwind CSS
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Input } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ field: { width: 256, borderRadius: 12, borderWidth: 1, borderStyle: "solid", borderColor: "color-mix(in oklab, var(--border) 80%, transparent)", backgroundColor: "var(--default)", color: "var(--foreground)", "::placeholder": { color: "var(--muted)" }, },});export function CustomStyles() { return ( <Input aria-label="Search projects" xstyle={styles.field} placeholder="Search projects..." /> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Global CSS
The base class .input powers every instance. Override it once with @layer components.
@layer components { .input { @apply rounded-lg border border-border bg-surface px-4 py-2 text-sm shadow-sm transition-colors;
&:hover, &[data-hovered="true"] { @apply bg-surface-secondary border-border/80; }
&:focus-visible, &[data-focus-visible="true"] { @apply border-accent ring-2 ring-accent/20; }
&[data-invalid="true"] { @apply border-danger bg-danger-soft text-danger; } }}Styling Reference
HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
Base Classes [!toc]
.input– Native input element styling
Interactive States
- Hover:
:hoveror[data-hovered="true"] - Focus Visible:
:focus-visibleor[data-focus-visible="true"] - Invalid:
[data-invalid="true"](also syncs witharia-invalid) - Disabled:
:disabledor[aria-disabled="true"] - Read Only:
[aria-readonly="true"]
API Reference
Input
Input accepts all standard HTML <input> attributes plus the following:
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Tailwind classes merged with the component styles. |
type | string | "text" | Input type (text, email, password, number, etc.). |
value | string | - | Controlled value. |
defaultValue | string | - | Uncontrolled initial value. |
onChange | (event: React.ChangeEvent<HTMLInputElement>) => void | - | Change handler. |
placeholder | string | - | Placeholder text. |
disabled | boolean | false | Disables the input. |
readOnly | boolean | false | Makes the input read-only. |
required | boolean | false | Marks the input as required. |
name | string | - | Name for form submission. |
autoComplete | string | - | Autocomplete hint for the browser. |
maxLength | number | - | Maximum number of characters. |
minLength | number | - | Minimum number of characters. |
pattern | string | - | Regex pattern for validation. |
min | number | string | - | Minimum value (for number/date inputs). |
max | number | string | - | Maximum value (for number/date inputs). |
step | number | string | - | Stepping interval (for number inputs). |
fullWidth | boolean | false | Whether 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, isRequired, and error handling, use TextField with Input as a child component.