Input
A single line field with clear labels and useful states.
fieldform
Preview
Input preview
Live · keyboard ready
When to use
- Any single-line text value in a form, such as name, email, or URL.
- Fields whose helper or error copy changes as the person types, where the message should reword in place.
- Plain form posts, since it forwards name and every native input attribute.
When not to use
- Use textarea for multi-line text.
- Use password-field, search-field, or number-field when the value has that shape.
- Use inline-edit for a value shown as page text and edited in place.
shadcn CLI
Also installs (1)
- manicat-foundation
Manual install(+)
registry.jsonjson
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "input",
"type": "registry:ui",
"title": "Input",
"description": "A single line field with clear labels and useful states.",
"categories": [
"inputs"
],
"dependencies": [
"motion"
],
"registryDependencies": [
"https://manicat.viraza.net/r/manicat-foundation.json"
],
"files": [
{
"path": "registry/components/input/input.tsx",
"type": "registry:component",
"target": "@components/manicat/input/input.tsx"
},
{
"path": "registry/components/input/input.module.css",
"type": "registry:component",
"target": "@components/manicat/input/input.module.css"
}
],
"docs": "Docs and live preview: https://uiarc.dev/components/input",
"meta": {
"tier": "free",
"kind": "component",
"docs": "https://manicat.viraza.net/components/input",
"markdown": "https://uiarc.dev/components/input/markdown",
"tags": [
"field",
"form"
]
}
}Usage
Install the component, then copy this into your app. Change the content and the props to fit your screen.
example.tsxtsx
"use client";
import { Input } from "@/components/manicat/input/input";
export function InputExample() {
return (
<div className="grid w-full max-w-sm gap-4">
<Input label="Email" placeholder="ada@example.com" description="We only use it for receipts." />
<Input label="Team URL" defaultValue="arc-labs" error="That URL is already taken." />
<Input label="Disabled" placeholder="Locked" disabled />
</div>
);
}
Examples
Real screens rather than isolated props. Switch to Code to copy a whole example into your project.
Locked field A disabled input that explains why it can't be edited.
Locked field
A disabled input that explains why it can't be edited. preview
Live · keyboard ready
locked-field-a-disabled-input-that-explains-why-it-can-t-be-edited-.tsxtsx
"use client";
import { Input } from "@/components/manicat/input/input";
export function InputLockedExample() {
return (
<div className="grid w-full max-w-sm gap-4">
<Input label="Workspace URL" defaultValue="acme.manicat.dev" disabled description="Ask an owner to change the workspace URL." />
</div>
);
}
Sign up form Labels, helper text and an inline error that appears once the address is invalid.
Sign up form
Labels, helper text and an inline error that appears once the address is invalid. preview
Live · keyboard ready
sign-up-form-labels-helper-text-and-an-inline-error-that-appears-once-the-address-is-invalid-.tsxtsx
"use client";
import { useState } from "react";
import { Button } from "@/components/manicat/button/button";
import { Input } from "@/components/manicat/input/input";
export function InputSignupExample() {
const [email, setEmail] = useState("ada@");
const [touched, setTouched] = useState(false);
const invalid = touched && !/^\S+@\S+\.\S+$/.test(email);
return (
<form
className="grid w-full max-w-sm gap-4"
onSubmit={(event) => {
event.preventDefault();
setTouched(true);
}}
>
<Input label="Full name" placeholder="Ada Lovelace" autoComplete="name" />
<Input
label="Work email"
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
onBlur={() => setTouched(true)}
description="We send the receipt here."
error={invalid ? "Enter a valid email address." : undefined}
/>
<Button type="submit">Create account</Button>
</form>
);
}
Accessibility
- Renders a native input with a real label, so focus and form behavior are native.
- Description and error ids are merged into aria-describedby alongside any caller value.
- Errors set aria-invalid and announce through role="alert"; animated words are aria-hidden with a plain screen reader copy.
Motion
- Helper and error rows open their height on a smooth spring, then changed words rise in and unblur while numbers roll digit by digit.
- Reduced motion mounts rows at full height and swaps words with an instant fade.
Responsive behavior
- The field fills its grid column with min-width 0, so it shrinks inside narrow layouts without overflowing.
- Text stays at the small size on touch, unlike password-strength, so iOS may zoom on focus if your --text-sm is below 16px.
- Hover border styles apply only on hover-capable fine pointers.
Performance
- One ResizeObserver per field measures the helper row for its height spring; cheap for a form, but avoid hundreds in a table.
- Only changed words animate, and numbers roll only the digits that changed.
Notes for AI
- Default single-line text field. Use password-field, search-field, or number-field when the value has that shape.
- Works controlled or uncontrolled like a native input; pass name for plain form submission.
- Changing the error string rewords it in place, so derive it from state instead of toggling separate messages.