Skip to main content

File

file selects one local file and persists only the string | number value returned by the upload executor. The browser File object is transport data only; it is never stored in DyonaFormValues.

Try it live​

Try it live in the Lab

Field contract​

A File field requires uploadSource.sourceId. accept is optional and contains the extensions or MIME types accepted by this schema; DYONA does not impose a whitelist. maxFileSizeBytes is optional and must be a positive finite number.

{
name: 'document',
label: 'Document',
type: 'file',
required: true,
uploadSource: {sourceId: 'documents'},
accept: ['.pdf', '.jpg', '.jpeg', '.png', '.webp', '.xls', '.xlsx', '.csv', '.doc', '.docx', '.txt'],
maxFileSizeBytes: 10_000_000,
}

The control checks the selected file against accept and maxFileSizeBytes before starting the upload.

Executor, progress, and cancellation​

Provide fileUploadExecutor to DyonaForm. It receives the file, an AbortSignal, a 0..100 progress callback, and contextual field data. The control shows determinate progress and exposes Cancel while uploading. Cancellation keeps the previous persisted value unchanged.

DYONA Form does not implement the backend or transport: the consumer owns HTTP, authentication, storage, retries, and server-side validation.

Complete example​

import {useCallback, useState} from 'react';
import {
DyonaForm,
type DyonaFileUploadExecutor,
type DyonaFormSchema,
type DyonaFormValues,
} from '@typhonsoftware/dyona-form';

const schema: DyonaFormSchema = {
title: 'Document upload',
hideSingleTab: true,
tabs: [{id: 'documents', title: 'Document', rows: [{columns: [{
name: 'document',
label: 'Document',
type: 'file',
required: true,
uploadSource: {sourceId: 'documents'},
accept: ['.pdf', '.jpg', '.jpeg', '.png', '.webp', '.xls', '.xlsx', '.csv', '.doc', '.docx', '.txt'],
maxFileSizeBytes: 10_000_000,
}]}]}],
};

export function DocumentForm() {
const [submittedValues, setSubmittedValues] = useState<DyonaFormValues | null>(null);
const fileUploadExecutor = useCallback<DyonaFileUploadExecutor>((request) => new Promise((resolve, reject) => {
let progress = 0;
let timer: number | null = null;
const cancel = () => {
if (timer !== null) window.clearInterval(timer);
reject(new DOMException('Upload cancelled', 'AbortError'));
};
if (request.signal.aborted) return cancel();
request.signal.addEventListener('abort', cancel, {once: true});
request.onProgress(0);
timer = window.setInterval(() => {
progress += 10;
request.onProgress(progress);
if (progress === 100) {
window.clearInterval(timer!);
request.signal.removeEventListener('abort', cancel);
resolve({value: 'FILE-DEMO-001'});
}
}, 160);
}), []);

return <>
<DyonaForm schema={schema} fileUploadExecutor={fileUploadExecutor} onSubmit={setSubmittedValues} />
{submittedValues && <pre>{JSON.stringify(submittedValues, null, 2)}</pre>}
</>;
}

After a successful upload, onSubmit receives the persisted value, for example:

{document: 'FILE-DEMO-001'}