Files
CIAgent/apps/web/components/ui/form-field.tsx
T
saksham 1a4c80958f Initial commit: CI Agent competitive-intelligence monitoring app
FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring,
source collection, LLM-based change analysis, enrichment, and account
security (Turnstile, escalating lockout, email verification).
2026-08-05 10:48:20 -04:00

45 lines
1.3 KiB
TypeScript

import { type InputHTMLAttributes, forwardRef } from "react";
import clsx from "clsx";
interface FormFieldProps extends InputHTMLAttributes<HTMLInputElement> {
label: string;
error?: string;
hint?: string;
}
export const FormField = forwardRef<HTMLInputElement, FormFieldProps>(
({ label, error, hint, id, className, ...props }, ref) => {
const fieldId = id ?? props.name;
return (
<div>
<label htmlFor={fieldId} className="block text-sm font-medium text-slate-700">
{label}
</label>
<input
ref={ref}
id={fieldId}
className={clsx(
"focus-ring mt-1 block w-full rounded-md border border-slate-300 px-3 py-2 text-sm shadow-sm",
error && "border-red-400",
className,
)}
aria-invalid={error ? "true" : "false"}
aria-describedby={error ? `${fieldId}-error` : hint ? `${fieldId}-hint` : undefined}
{...props}
/>
{hint && !error && (
<p id={`${fieldId}-hint`} className="mt-1 text-xs text-slate-500">
{hint}
</p>
)}
{error && (
<p id={`${fieldId}-error`} className="mt-1 text-xs text-red-600" role="alert">
{error}
</p>
)}
</div>
);
},
);
FormField.displayName = "FormField";