File Inputs
type="file" stores the real File object, not the C:\fakepath string - with single and multiple support.
With a native <input type="file">, the field's value is the useless C:\fakepath\… string.
gform-react fixes this: a GInput with type="file" stores the real File object (or File[]
with multiple) in form state.
Single file
File inputs are intentionally uncontrolled - the DOM owns the FileList, so you don't pass a
value. The current selection is reflected into state on change.
import { GForm, GInput, GValidator, type GValidators } from "gform-react";
interface CvForm {
cv: File | null;
}
const validators: GValidators<CvForm> = {
cv: new GValidator().withRequiredMessage("Please attach your CV"),
};
export default function UploadCv() {
return (
<GForm<CvForm>
validators={validators}
onSubmit={(state, e) => {
e.preventDefault();
const data = state.toFormData(); // includes the file
// upload `data` via your service…
}}
>
<GInput
formKey="cv"
type="file"
required
accept=".pdf,.doc,.docx"
element={(input, props) => (
<div>
<input {...props} />
{/* show the chosen file name from state */}
{input.value && <small>{(input.value as File).name}</small>}
{input.error && <small className="error">{input.errorText}</small>}
</div>
)}
/>
<button>Upload</button>
</GForm>
);
}- Single file →
state.cv.valueisFile | null. - With
multiple→state.cv.valueisFile[].
Multiple files
Add the native multiple attribute; input.value becomes a File[].
<GInput
formKey="attachments"
type="file"
multiple
element={(input, props) => (
<div>
<input {...props} />
<ul>
{(input.value as File[] | null)?.map((file) => (
<li key={file.name}>{file.name}</li>
))}
</ul>
</div>
)}
/>Because file inputs are uncontrolled, you can't programmatically set the selected files via value
- the browser doesn't allow it.
input.valuealways reflects the user's current selection.
Submitting files
state.toFormData() produces a FormData instance with file fields included automatically (via the
underlying <form>), ready to POST to your endpoint or pass to a Server Action.
onSubmit={(state, e) => {
e.preventDefault();
fetch("/api/upload", { method: "POST", body: state.toFormData() });
}}