{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "field", "title": "Field", "description": "Form field wrapper that provides a label, description, and error message around a form control.", "registryDependencies": [ "label", "separator" ], "files": [ { "path": "packages/ui/src/field.tsx", "content": "\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { useMemo } from \"react\";\nimport { Label } from \"./label\";\nimport { Separator } from \"./separator\";\nimport { cn } from \"./utils\";\n\n// =============================================================================\n// FieldSet\n// =============================================================================\nexport interface FieldSetProps extends React.ComponentProps<\"fieldset\"> {}\n\nexport function FieldSet({ className, ...props }: FieldSetProps) {\n return (\n [data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3\",\n className\n )}\n data-slot=\"field-set\"\n {...props}\n />\n );\n}\n\n// =============================================================================\n// FieldLegend\n// =============================================================================\nexport interface FieldLegendProps extends React.ComponentProps<\"legend\"> {\n /**\n * Visual variant of the legend\n * @default \"legend\"\n */\n variant?: \"legend\" | \"label\";\n}\n\nexport function FieldLegend({\n className,\n variant = \"legend\",\n ...props\n}: FieldLegendProps) {\n return (\n \n );\n}\n\n// =============================================================================\n// FieldGroup\n// =============================================================================\nexport interface FieldGroupProps extends React.ComponentProps<\"div\"> {}\n\nexport function FieldGroup({ className, ...props }: FieldGroupProps) {\n return (\n [data-slot=field-group]]:gap-4\",\n className\n )}\n data-slot=\"field-group\"\n {...props}\n />\n );\n}\n\n// =============================================================================\n// Field\n// =============================================================================\nconst fieldVariants = cva(\n \"group/field flex w-full gap-2 data-[invalid=true]:text-destructive\",\n {\n variants: {\n orientation: {\n vertical: \"flex-col [&>*]:w-full [&>.sr-only]:w-auto\",\n horizontal:\n \"flex-row items-center has-[>[data-slot=field-content]]:items-start [&>[data-slot=field-label]]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px\",\n responsive:\n \"@md/field-group:flex-row flex-col @md/field-group:items-center @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:[&>*]:w-auto [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px\",\n },\n },\n defaultVariants: {\n orientation: \"vertical\",\n },\n }\n);\n\nexport interface FieldProps\n extends React.ComponentProps<\"div\">,\n VariantProps {}\n\nexport function Field({\n className,\n orientation = \"vertical\",\n ...props\n}: FieldProps) {\n return (\n \n );\n}\n\n// =============================================================================\n// FieldContent\n// =============================================================================\nexport interface FieldContentProps extends React.ComponentProps<\"div\"> {}\n\nexport function FieldContent({ className, ...props }: FieldContentProps) {\n return (\n \n );\n}\n\n// =============================================================================\n// FieldLabel\n// =============================================================================\nexport interface FieldLabelProps extends React.ComponentProps {}\n\nexport function FieldLabel({ className, ...props }: FieldLabelProps) {\n return (\n [data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border has-[>[data-slot=field]]:border-primary/10 has-data-checked:border-primary/30 has-data-checked:bg-primary/5 group-data-[disabled=true]/field:opacity-50 dark:has-data-checked:bg-primary/10 [&>*]:data-[slot=field]:p-2.5\",\n \"has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col\",\n className\n )}\n data-slot=\"field-label\"\n {...props}\n />\n );\n}\n\n// =============================================================================\n// FieldTitle\n// =============================================================================\nexport interface FieldTitleProps extends React.ComponentProps<\"div\"> {}\n\nexport function FieldTitle({ className, ...props }: FieldTitleProps) {\n return (\n \n );\n}\n\n// =============================================================================\n// FieldDescription\n// =============================================================================\nexport interface FieldDescriptionProps extends React.ComponentProps<\"p\"> {}\n\nexport function FieldDescription({\n className,\n ...props\n}: FieldDescriptionProps) {\n return (\n a]:underline [&>a]:underline-offset-4 [&>a]:hover:text-primary\",\n \"group-data-[invalid=true]/field:text-destructive\",\n className\n )}\n data-slot=\"field-description\"\n {...props}\n />\n );\n}\n\n// =============================================================================\n// FieldSeparator\n// =============================================================================\nexport interface FieldSeparatorProps extends React.ComponentProps<\"div\"> {\n children?: React.ReactNode;\n}\n\nexport function FieldSeparator({\n children,\n className,\n ...props\n}: FieldSeparatorProps) {\n return (\n \n \n {children && (\n \n {children}\n \n )}\n \n );\n}\n\n// =============================================================================\n// FieldError\n// =============================================================================\nexport interface FieldErrorProps extends React.ComponentProps<\"div\"> {\n /**\n * Array of error objects with message property\n */\n errors?: Array<{ message?: string } | undefined>;\n}\n\nexport function FieldError({\n className,\n children,\n errors,\n ...props\n}: FieldErrorProps) {\n const content = useMemo(() => {\n if (children) {\n return children;\n }\n\n if (!errors?.length) {\n return null;\n }\n\n const uniqueErrors = [\n ...new Map(errors.map((error) => [error?.message, error])).values(),\n ];\n\n if (uniqueErrors?.length === 1) {\n return uniqueErrors[0]?.message;\n }\n\n return (\n
    \n {uniqueErrors.map(\n (error, index) =>\n error?.message &&
  • {error.message}
  • \n )}\n
\n );\n }, [children, errors]);\n\n if (!content) {\n return null;\n }\n\n return (\n \n {content}\n \n );\n}\n", "type": "registry:ui" } ], "type": "registry:ui" }