Form Control

PreviousNext

A container component that wraps form inputs with labels, descriptions, and error messages, providing consistent layout and validation state management

'use client';

import { FormControl } from '@/ui/forms/FormControl';

export function FormControlDemo() {
  return (
    <FormControl
      id="email"
      label="Email Address"
      description="We'll never share your email"
      required
      className="max-w-md"
    >
      <input
        id="email"
        type="email"
        placeholder="Enter your email"
        className="rounded border border-grey px-12 py-8 w-full"
      />
    </FormControl>
  );
}

Installation

npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/form-control.json

Usage

'use client';
 
import { useState } from 'react';
import { FormControl } from '@/docs/lib/ui/forms/form-control';
 
export function Component() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');
 
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setEmail(e.target.value);
    if (!e.target.value.includes('@')) {
      setError('Please enter a valid email address');
    } else {
      setError('');
    }
  };
 
  return (
    <FormControl
      id="email"
      label="Email Address"
      description="We'll never share your email"
      required
      validationStatus={error ? 'error' : 'default'}
      errorMessage={error}
      className="max-w-md"
    >
      <input
        id="email"
        type="email"
        value={email}
        onChange={handleChange}
        className="rounded border border-grey px-12 py-8 w-full"
      />
    </FormControl>
  );
}

API Reference

FormControl

PropTypeDefaultDescription
childrenReactNodeundefinedThe form input element(s) to render inside the form control
idstringundefinedUnique identifier that links the label to the input element. Required when using a label
labelReactNodeundefinedLabel text or content to display above the input. Only renders when both label and id are provided
labelClassNamestringundefinedAdditional CSS classes to apply to the FormLabel component
descriptionstringundefinedHelper text displayed alongside the label
disabledbooleanundefinedWhen true, hides error messages and applies disabled state via useInternalStatus
requiredbooleanundefinedMarks the field as required and displays a required star indicator in the label
hideRequiredStarbooleanundefinedWhen true, hides the required star even when the field is required
layout"horizontal" | "vertical" | "horizontal-${string}"undefinedControls the layout orientation of the label. Passed to FormLabel component
validationStatus"default" | "error" | "success""default"Visual validation state of the form control. Use "error" to display error messages
errorMessagestringundefinedError message to display below the input when validationStatus is "error" and the field is not disabled
dataTestIdstringundefinedCustom data-testid attribute for testing purposes
dataNamestringundefinedCustom data-name attribute for styling and identification
classNamestringundefinedAdditional CSS classes to apply to the outer container div
valueValueundefinedGeneric value prop that can be passed through (type parameter, not commonly used directly)
onChange(name: string, value: Value) => voidundefinedGeneric onChange handler (type parameter, not commonly used directly)

The FormControl component also inherits props from FormLabelProps and supports generic type parameters for flexible value and attribute types.

Notes

  • Layout container: FormControl provides a consistent flex column layout with gap-4 spacing between label, input, and error message
  • Label integration: Automatically renders a FormLabel component when both label and id props are provided
  • Conditional error display: Error messages only appear when validationStatus is "error" and the field is not disabled
  • Internal status management: Uses the useInternalStatus hook to coordinate validation status and disabled state. When disabled, the internal status becomes "disabled" which hides error messages
  • Generic type support: Supports generic type parameters for flexible value types and HTML attribute types, making it reusable across different input types
  • FormLabel delegation: Passes description, layout, required, hideRequiredStar, and labelClassName props to the FormLabel component for consistent label rendering
  • Error component: Uses FormControlError component to display error messages with proper styling and accessibility attributes
  • Data attributes: Supports custom data-name and data-testid attributes for styling and testing
  • Composition pattern: Designed as a composition wrapper that accepts any form input as children, providing flexibility for different input types (text, select, textarea, etc.)
  • Accessibility: Properly links labels to inputs via the id prop, ensuring screen readers can associate labels with their inputs
  • Client component: This is a client component that requires the "use client" directive due to the useInternalStatus hook