Skip to main content

Input

Fundamental component for inputs.

Pair with Field.* for label/description/error wiring in forms:

Validation States:

The value entered for the error input has failed validation.
import { Field } from "@ngrok/mantle/field";import { Input } from "@ngrok/mantle/input"; <Field.Item className="max-w-80" name="username">	<Field.Label>Username</Field.Label>	<Field.Control>		<Input placeholder="Enter a username" />	</Field.Control></Field.Item><Field.Item className="max-w-80" name="email">	<Field.Label>Email</Field.Label>	<Field.Control>		<Input placeholder="Enter your email" autoComplete="email" />	</Field.Control></Field.Item> <Field.Item name="error">	<Field.Label>Error</Field.Label>	<Field.Control>		<Input validation="error" />	</Field.Control></Field.Item><Field.Item name="success">	<Field.Label>Success</Field.Label>	<Field.Control>		<Input validation="success" />	</Field.Control></Field.Item><Field.Item name="warning">	<Field.Label>Warning</Field.Label>	<Field.Control>		<Input validation="warning" />	</Field.Control></Field.Item>

Or render the control on its own:

import { Input } from "@ngrok/mantle/input"; <Input placeholder="Enter a username" />;

Examples

With TanStack Form

Use @tanstack/react-form with zod when the input needs controlled value, blur, submit, and validation state. Field.Item owns the field name and Field.Errors renders normalized validator messages.

import { Button } from "@ngrok/mantle/button";import { Field, toErrorMessages } from "@ngrok/mantle/field";import { Input } from "@ngrok/mantle/input";import { useForm } from "@tanstack/react-form";import { z } from "zod"; export const formSchema = z.object({	email: z.string().email("Enter a valid email address."),});function Example() {	const defaultValues = {		email: "",	};	const form = useForm({		defaultValues,		validators: {			onSubmit: formSchema,		},		onSubmit: ({ value }) => {			// Handle form submission here		},	}); 	return (		<form			onSubmit={(event) => {				event.preventDefault();				event.stopPropagation();				void form.handleSubmit();			}}		>			<form.Field name="email">				{(field) => (					<Field.Item name={field.name}>						<Field.Label>Email</Field.Label>						<Field.Control>							<Input								type="email"								value={field.state.value}								onBlur={field.handleBlur}								onChange={(event) => field.handleChange(event.target.value)}							/>						</Field.Control>						<Field.Errors messages={toErrorMessages(field.state.meta.errors)} />					</Field.Item>				)}			</form.Field>			<Button type="submit" appearance="filled" intent="neutral">				Submit			</Button>		</form>	);}

Child elements

Compose additional visual or functional elements within the Input using children. The examples below show how to render start and end icons or buttons. The Password Input is built with this API under the hood! You must also pass the InputCapture component as children, because it renders the actual form input element! When you do not use the children API, Input renders an InputCapture for you.

When composing with interactive content (e.g. a button), consider whether that element should be tab-indexable or receive focus!

The value entered for the search-start-error input has failed validation.
The value entered for the search-end-error input has failed validation.
The value entered for the search-both-error input has failed validation.
import { Field } from "@ngrok/mantle/field";import { Input, InputCapture } from "@ngrok/mantle/input";import { InfoIcon } from "@phosphor-icons/react/Info";import { MagnifyingGlassIcon } from "@phosphor-icons/react/MagnifyingGlass"; <Field.Item className="max-w-80" name="search-start">	<Field.Label>Search with start icon</Field.Label>	<Field.Control>		<Input className="max-w-64" placeholder="Search...">			<MagnifyingGlassIcon />			<InputCapture />		</Input>	</Field.Control></Field.Item><Field.Item className="max-w-80" name="search-end">	<Field.Label>Search with end icon</Field.Label>	<Field.Control>		<Input className="max-w-64" placeholder="Search...">			<InputCapture />			<InfoIcon />		</Input>	</Field.Control></Field.Item><Field.Item className="max-w-80" name="search-both">	<Field.Label>Search with start and end icons</Field.Label>	<Field.Control>		<Input className="max-w-64" placeholder="Search...">			<MagnifyingGlassIcon />			<InputCapture />			<InfoIcon />		</Input>	</Field.Control></Field.Item>

When to use InputCapture

For 90% of cases (a simple input with optional icons or validation), pass children directly to <Input> or omit children entirely. The Input renders an InputCapture for you internally, so you do not need to import or render it yourself.

InputCapture is the actual <input> element wrapper. Reach for it only when composing custom adornments: for example, a left-side prefix and a right-side suffix where the existing Input slots don't fit. When you supply your own children, you must include <InputCapture /> so the form input element is still rendered. The Password Input is built using this API under the hood.

API Reference

The Input accepts the following props in addition to the standard HTML input attributes.

PropTypeDefaultDescription
validation"error" | "success" | "warning" | false | () => "error" | "success" | "warning" | falseUse the validation prop to show if the input has a specific validation status. This will change the border and outline of the input. The false type is useful when using short-circuiting logic so that you don't need to use a ternary with undefined. Setting validation to error also sets aria-invalid.

Two standard attributes are narrowed to unions, so a typo is a type error: type accepts the native input type names, and autoComplete accepts the HTML autocomplete tokens.

InputCapture

The <input> element itself. Input renders one for you unless you pass children; then you render it yourself among your adornments. It accepts the same props as Input, minus children, and reads any prop you set on the surrounding Input through context, so id, name, type, validation, and the aria-* attributes land on the element whichever of the two you set them on.

Data AttributeValueDescription
data-slot"input"The chrome around the input.
data-slot"input-capture"The <input> element.
data-disabledpresent when disabledOn the chrome. Style with data-disabled:.
data-validation"error" | "success" | "warning"On the chrome and the <input>. Omitted when unset.