Bloom Logo

Form Field

A composite form layout wrapper that connects labels, input fields, helper text, and validation error messages.

formField.tsx

Core implementation of the FormField component.

ReactTailwindFormsUI Layout
"use client";

import * as React from "react";
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/label/label";

export interface FormFieldProps extends React.HTMLAttributes<HTMLDivElement> {
  label?: React.ReactNode;
  isRequired?: boolean;
  description?: React.ReactNode;
  errorMessage?: React.ReactNode;
  isInvalid?: boolean;
  htmlFor?: string;
}

export function FormField({
  className,
  children,
  label,
  isRequired = false,
  description,
  errorMessage,
  isInvalid = false,
  htmlFor,
  ...props
}: FormFieldProps) {
  const generatedId = React.useId();
  const fieldId = htmlFor || generatedId;

  return (
    <div className={cn("w-full flex flex-col gap-1.5", className)} {...props}>
      {label && (
        <Label htmlFor={fieldId} isRequired={isRequired}>
          {label}
        </Label>
      )}
      <div className="w-full">
        {React.isValidElement(children)
          ? React.cloneElement(children as React.ReactElement<{ id?: string; isInvalid?: boolean }>, {
              id: fieldId,
              isInvalid: isInvalid || Boolean(errorMessage),
            })
          : children}
      </div>
      {isInvalid && errorMessage ? (
        <p className="text-xs text-danger font-medium">{errorMessage}</p>
      ) : description ? (
        <p className="text-xs text-muted-foreground">{description}</p>
      ) : null}
    </div>
  );
}

Basic Usage

Form field with label, description and error states.

We will send a confirmation email here.

Username is already taken

API Reference

Props — FormField

Properties to configure the FormField component.

PropTypeDefaultDescription
labelReactNodeLabel title text.
errorMessageReactNodeError message shown when invalid.