Field
Compound form field with label, description, and error message support.
We'll never share your email.
Web preview — components render natively on iOS & Android
import { Field, FieldLabel, FieldDescription, FieldError } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
export function MyScreen() {
return (
<Field>
<FieldLabel>Email</FieldLabel>
<Input placeholder="you@example.com" />
<FieldDescription>We'll never share your email.</FieldDescription>
</Field>
);
}Installation#
npx @aniui/cli add fieldUsage#
app/index.tsx
import { Field, FieldLabel, FieldDescription, FieldError } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
export function MyScreen() {
return (
<Field>
<FieldLabel>Email</FieldLabel>
<Input placeholder="you@example.com" />
<FieldDescription>We'll never share your email.</FieldDescription>
</Field>
);
}Horizontal Layout#
As it appears on your ID.
Web preview — components render natively on iOS & Android
import { Field, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
export function MyScreen() {
return (
<Field orientation="horizontal">
<FieldLabel>Name</FieldLabel>
<Input placeholder="John Doe" />
</Field>
);
}Error State#
Password must be at least 8 characters.
Web preview — components render natively on iOS & Android
import { Field, FieldLabel, FieldError } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
export function MyScreen() {
return (
<Field>
<FieldLabel>Email</FieldLabel>
<Input placeholder="you@example.com" />
<FieldError errors={["Email is required", "Must be a valid email"]} />
</Field>
);
}Components#
Field is a compound component made up of several parts:
ComponentDescription
FieldRoot component that provides orientation context. Wraps label, input, description, and error.
FieldLabelStyled label text. Adjusts layout based on orientation.
FieldDescriptionHelper text displayed below the input.
FieldErrorDisplays one or more error messages. Renders nothing when no errors are present.
Props#
Field#
PropTypeDefault
orientation"vertical" | "horizontal""vertical"classNamestring-childrenReact.ReactNode-Also accepts all View props from React Native.
FieldLabel#
PropTypeDefault
classNamestring-Also accepts all Text props from React Native.
FieldDescription#
PropTypeDefault
classNamestring-Also accepts all Text props from React Native.
FieldError#
PropTypeDefault
errorsstring[]-classNamestring-childrenReact.ReactNode-Also accepts all View props from React Native.
Accessibility#
FieldLabelusesaccessibilityRole="text"for screen readers.FieldErrorusesaccessibilityRole="alert"to announce errors.- Horizontal layout maintains minimum touch target with
min-w-[100px]on the label.
Source#
components/ui/field.tsx
import React, { createContext, useContext } from "react";
import { View, Text } from "react-native";
import { cn } from "@/lib/utils";
type Orientation = "vertical" | "horizontal";
const FieldContext = createContext<{ orientation: Orientation }>({
orientation: "vertical",
});
export interface FieldProps extends React.ComponentPropsWithoutRef<typeof View> {
className?: string;
orientation?: Orientation;
children?: React.ReactNode;
}
export function Field({ orientation = "vertical", className, children, ...props }: FieldProps) {
return (
<FieldContext.Provider value={{ orientation }}>
<View
className={cn(
orientation === "vertical" ? "gap-1.5" : "flex-row items-start gap-3",
className
)}
{...props}
>
{children}
</View>
</FieldContext.Provider>
);
}
export interface FieldLabelProps extends React.ComponentPropsWithoutRef<typeof Text> {
className?: string;
}
export function FieldLabel({ className, ...props }: FieldLabelProps) {
const { orientation } = useContext(FieldContext);
return (
<Text
className={cn(
"text-sm font-medium text-foreground",
orientation === "horizontal" && "min-w-[100px] pt-3",
className
)}
accessibilityRole="text"
{...props}
/>
);
}
export interface FieldDescriptionProps extends React.ComponentPropsWithoutRef<typeof Text> {
className?: string;
}
export function FieldDescription({ className, ...props }: FieldDescriptionProps) {
return (
<Text className={cn("text-xs text-muted-foreground", className)} {...props} />
);
}
export interface FieldErrorProps extends React.ComponentPropsWithoutRef<typeof View> {
className?: string;
errors?: string[];
children?: React.ReactNode;
}
export function FieldError({ className, errors, children, ...props }: FieldErrorProps) {
if (!errors?.length && !children) return null;
return (
<View className={cn("gap-0.5", className)} accessibilityRole="alert" {...props}>
{errors?.map((err, i) => (
<Text key={i} className="text-sm text-destructive">{err}</Text>
))}
{children}
</View>
);
}