Form
tetra-ui/formFreeComponent
Components and utilities that help you compose forms with react-hook-form.
Live preview
live · rendered by the registry
Rendered by tetra-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://tetra-ui.com/r/form.jsonSource
1import {2 Children,3 cloneElement,4 createContext,5 useContext,6 useMemo,7} from "react";8import type { FieldErrors, FieldPath } from "react-hook-form";9import { get } from "react-hook-form";10import { Text, type TextProps, View } from "react-native";11import { cn } from "../lib/utils";12import { Label, type LabelProps } from "./label";1314// Types15type FieldStateProps = {16 invalid?: boolean;17 disabled?: boolean;18};1920type InternalFieldContextType = FieldStateProps & {21 errorMessage?: string;22};2324export type FieldProps = InternalFieldContextType & {25 children: React.ReactNode;26};2728type FieldControlProps = {29 children: React.ReactElement<FieldStateProps>;30};3132// Context33const FieldContext = createContext<InternalFieldContextType | null>(null);3435const useFieldContext = () => {36 const context = useContext(FieldContext);37 if (!context) {38 throw new Error("useFieldContext must be used within a Field component");39 }40 return context;41};4243// Components44export const Field = ({45 errorMessage,46 invalid,47 disabled,48 children,49}: FieldProps) => {50 const ctx = useMemo(51 () => ({ disabled, errorMessage, invalid }),52 [errorMessage, disabled, invalid]53 );5455 return (56 <FieldContext.Provider value={ctx}>57 <View className="flex flex-col gap-2">{children}</View>58 </FieldContext.Provider>59 );60};6162export const FieldLabel = ({ className, ...props }: LabelProps) => {63 const { disabled, invalid } = useFieldContext();6465 return (66 <Label67 {...props}68 className={cn(69 {70 "text-destructive": invalid,71 "text-muted-foreground": disabled,72 },73 className74 )}75 />76 );77};7879export const FieldControl = ({ children }: FieldControlProps) => {80 const { disabled, invalid } = useFieldContext();81 const child = Children.only(children);8283 if (!child) {84 if (__DEV__) {85 throw new Error(86 "FieldControl expects a single React element as children"87 );88 }8990 return null;91 }9293 return cloneElement(child, {94 disabled,95 invalid,96 });97};9899export const FieldDescription = ({ className, ...props }: TextProps) => {100 const { errorMessage } = useFieldContext();101102 if (errorMessage) {103 return null;104 }105106 return (107 <Text108 {...props}109 className={cn("text-muted-foreground text-sm", className)}110 />111 );112};113114export const FieldErrorMessage = ({115 className,116 ...props117}: Omit<TextProps, "children">) => {118 const { errorMessage } = useFieldContext();119120// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from tetra-ui
All 41 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | tetra-ui | Components | Free | 1 dep | |
| Action Inputaction-input | tetra-ui | Components | Free | no deps | |
| Alertalert | tetra-ui | Components | Free | no deps | |
| Avataravatar | tetra-ui | Components | Free | no deps | |
| Badgebadge | tetra-ui | Components | Free | no deps | |
| Bottom Sheetbottom-sheet | tetra-ui | Components | Free | 4 deps · 7 files | |
| Buttonbutton | tetra-ui | Components | Free | no deps | |
| Cardcard | tetra-ui | Components | Free | no deps |
