turash/bugulma/frontend/components/ui/FormField.tsx

71 lines
1.6 KiB
TypeScript

import React from 'react';
import { clsx } from 'clsx';
export interface FormFieldProps {
label?: string;
description?: string;
error?: string;
required?: boolean;
children: React.ReactNode;
className?: string;
labelClassName?: string;
errorClassName?: string;
}
/**
* Form field wrapper with label, description, and error
*/
export const FormField = ({
label,
description,
error,
required,
children,
className,
labelClassName,
errorClassName,
}: FormFieldProps) => {
const fieldId = React.useId();
return (
<div className={clsx('flex flex-col gap-2', className)}>
{label && (
<label
htmlFor={fieldId}
className={clsx(
'text-sm font-medium text-foreground',
{
"after:content-['*'] after:ml-1 after:text-destructive": required,
},
labelClassName
)}
>
{label}
</label>
)}
{description && (
<p className="text-xs text-muted-foreground">{description}</p>
)}
<div>
{React.isValidElement(children)
? React.cloneElement(children as React.ReactElement, {
id: fieldId,
'aria-invalid': error ? 'true' : 'false',
'aria-describedby': error ? `${fieldId}-error` : undefined,
})
: children}
</div>
{error && (
<p
id={`${fieldId}-error`}
className={clsx('text-sm text-destructive', errorClassName)}
role="alert"
>
{error}
</p>
)}
</div>
);
};