Github

Input

A text input component for forms and user data entry with built-in styling and accessibility features.

import { Input } from "@/components/ui/input";
export function InputDemo() {	return (		<div className="w-full max-w-sm">			<Input type="email" placeholder="Email" />		</div>	);}

Installation

pnpm dlx shadcn@latest add @herocn/input

Usage

import { Input } from "@/components/ui/input"
<Input placeholder="Email" type="email" />

Examples

Variants

Use the variant prop for a softer background on the secondary style.

import { Input } from "@/components/ui/input";
export function InputVariants() {	return (		<div className="flex w-full max-w-sm flex-col gap-3">			<Input placeholder="Default" />			<Input variant="secondary" placeholder="Secondary" />		</div>	);}

States

Disabled inputs are non-interactive. Set aria-invalid for error styling (for example when validation fails).

import { Input } from "@/components/ui/input";
export function InputStates() {	return (		<div className="flex w-full max-w-sm flex-col gap-3">			<Input disabled placeholder="Disabled" />			<Input aria-invalid placeholder="Invalid" defaultValue="Invalid value" />		</div>	);}

With field

Pair Input with Field, FieldLabel, and FieldDescription for accessible labels and helper text.

Choose a unique username for your account.

import {	Field,	FieldDescription,	FieldLabel,} from "@/components/ui/field";import { Input } from "@/components/ui/input";
export function InputField() {	return (		<div className="w-full max-w-sm">			<Field>				<FieldLabel htmlFor="input-field-username">Username</FieldLabel>				<Input					id="input-field-username"					type="text"					placeholder="Enter your username"				/>				<FieldDescription>					Choose a unique username for your account.				</FieldDescription>			</Field>		</div>	);}

Field group

Stack multiple fields and actions with FieldGroup.

We'll send updates to this address.

import { Button } from "@/components/ui/button";import {	Field,	FieldDescription,	FieldGroup,	FieldLabel,} from "@/components/ui/field";import { Input } from "@/components/ui/input";
export function InputFieldgroup() {	return (		<div className="w-full max-w-sm">			<FieldGroup>				<Field>					<FieldLabel htmlFor="fieldgroup-name">Name</FieldLabel>					<Input id="fieldgroup-name" placeholder="Jordan Lee" />				</Field>				<Field>					<FieldLabel htmlFor="fieldgroup-email">Email</FieldLabel>					<Input						id="fieldgroup-email"						type="email"						placeholder="[email protected]"					/>					<FieldDescription>						We&apos;ll send updates to this address.					</FieldDescription>				</Field>				<Field orientation="horizontal">					<Button type="reset" variant="outline">						Reset					</Button>					<Button type="submit">Submit</Button>				</Field>			</FieldGroup>		</div>	);}

Label with badge

Use a badge in the label row for status or metadata (for example a feature flag).

import { Badge } from "@/components/ui/badge";import { Field, FieldLabel } from "@/components/ui/field";import { Input } from "@/components/ui/input";
export function InputBadge() {	return (		<div className="w-full max-w-sm">			<Field>				<FieldLabel					htmlFor="input-badge"					className="flex w-full items-center gap-2"				>					Webhook URL					<Badge variant="default" className="ml-auto">						Beta					</Badge>				</FieldLabel>				<Input					id="input-badge"					type="url"					placeholder="https://api.example.com/webhook"				/>			</Field>		</div>	);}

Input group

Prefix or suffix text and icons with InputGroup, InputGroupAddon, and InputGroupInput.

https://
import { InfoIcon } from "lucide-react";import { Field, FieldLabel } from "@/components/ui/field";import {	InputGroup,	InputGroupAddon,	InputGroupInput,	InputGroupText,} from "@/components/ui/input-group";
export function InputInputGroup() {	return (		<div className="w-full max-w-sm">			<Field>				<FieldLabel htmlFor="input-group-url">Website URL</FieldLabel>				<InputGroup>					<InputGroupInput id="input-group-url" placeholder="example.com" />					<InputGroupAddon>						<InputGroupText>https://</InputGroupText>					</InputGroupAddon>					<InputGroupAddon align="inline-end">						<InfoIcon />					</InputGroupAddon>				</InputGroup>			</Field>		</div>	);}

Button group

Place the input beside actions using ButtonGroup.

import { Button } from "@/components/ui/button";import { ButtonGroup } from "@/components/ui/button-group";import { Field, FieldLabel } from "@/components/ui/field";import { Input } from "@/components/ui/input";
export function InputButtonGroup() {	return (		<div className="w-full max-w-sm">			<Field>				<FieldLabel htmlFor="input-button-group">Search</FieldLabel>				<ButtonGroup>					<Input						id="input-button-group"						variant="secondary"						placeholder="Type to search..."					/>					<Button variant="tertiary">Search</Button>				</ButtonGroup>			</Field>		</div>	);}

In surface

Use variant="secondary" when placing an Input inside a card or panel surface for a subtler, shadow-free appearance that blends with the surface background.

import { Button } from "@/components/ui/button";import { Field, FieldLabel } from "@/components/ui/field";import { Input } from "@/components/ui/input";import { Surface } from "@/components/ui/surface";
export function InputInSurface() {	return (		<Surface className="flex w-full max-w-sm flex-col gap-3 rounded-3xl p-6">			<Field>				<FieldLabel htmlFor="input-in-surface-message">					What's your name?				</FieldLabel>				<Input id="input-in-surface-message" variant="secondary" />			</Field>			<Button>Submit</Button>		</Surface>	);}

RTL

لن نشارك بريدك الإلكتروني مع أي شخص.

"use client";
import {	type Translations,	useTranslation,} from "@/components/language-selector";import {	Field,	FieldDescription,	FieldLabel,} from "@/components/ui/field";import { Input } from "@/components/ui/input";
const translations: Translations = {	en: {		dir: "ltr",		values: {			nameLabel: "Full name",			namePlaceholder: "John Doe",			emailLabel: "Email address",			emailPlaceholder: "[email protected]",			emailDescription: "We'll never share your email with anyone.",		},	},	ar: {		dir: "rtl",		values: {			nameLabel: "الاسم الكامل",			namePlaceholder: "محمد علي",			emailLabel: "البريد الإلكتروني",			emailPlaceholder: "[email protected]",			emailDescription: "لن نشارك بريدك الإلكتروني مع أي شخص.",		},	},	he: {		dir: "rtl",		values: {			nameLabel: "שם מלא",			namePlaceholder: "ישראל ישראלי",			emailLabel: "כתובת דוא״ל",			emailPlaceholder: "[email protected]",			emailDescription: "לעולם לא נשתף את הדוא״ל שלך עם אחרים.",		},	},};
export function InputRtl() {	const { dir, language, t } = useTranslation(translations, "ar");
	return (		<div			className="flex w-full max-w-sm flex-col gap-4"			lang={language}			dir={dir}		>			<Field>				<FieldLabel htmlFor="form-input-rtl-name">{t.nameLabel}</FieldLabel>				<Input					type="text"					id="form-input-rtl-name"					placeholder={t.namePlaceholder}				/>			</Field>			<Field>				<FieldLabel htmlFor="form-input-rtl-email">{t.emailLabel}</FieldLabel>				<Input					type="email"					id="form-input-rtl-email"					placeholder={t.emailPlaceholder}				/>				<FieldDescription>{t.emailDescription}</FieldDescription>			</Field>		</div>	);}

API Reference

Input

The Input component accepts all props from a native <input> and @base-ui/react Input plus the following:

PropTypeDefault
variant"default" | "secondary"
"default"