File Input

File Input allows users to select and upload files. Supports labels, validation, helper text, and multiple file selection.

Basic Examples

File inputs with various configurations

const { default: FileInput } = await import('/components/data-input/file-input.js');
const { tags, $ } = Lightview;
const { div } = tags;

// 1. Basic file input
const basic = FileInput({});

// 2. With label and helper
const withLabel = FileInput({ 
    label: 'Upload Document',
    helper: 'PDF, DOC, or DOCX files only',
    accept: '.pdf,.doc,.docx'
});

// 3. Multiple files with color
const multiple = FileInput({ 
    label: 'Upload Images',
    accept: 'image/*',
    multiple: true,
    color: 'primary',
    helper: 'You can select multiple images'
});

// 4. Required file input
const required = FileInput({ 
    label: 'Resume',
    required: true,
    accept: '.pdf'
});

// Insert all examples
$('#example').content(
    div({ style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem' }, basic, withLabel, multiple, required)
);
const { default: FileInput } = await import('/components/data-input/file-input.js');
const { $ } = Lightview;

const demo = {
    tag: 'div',
    attributes: { style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem' },
    children: [
        { tag: FileInput },
        {
            tag: FileInput,
            attributes: { label: 'Upload Document', helper: 'PDF, DOC, or DOCX files only', accept: '.pdf,.doc,.docx' }
        },
        {
            tag: FileInput,
            attributes: { label: 'Upload Images', accept: 'image/*', multiple: true, color: 'primary', helper: 'You can select multiple images' }
        },
        {
            tag: FileInput,
            attributes: { label: 'Resume', required: true, accept: '.pdf' }
        }
    ]
};

$('#example').content(demo);
const { default: FileInput } = await import('/components/data-input/file-input.js');
const { tags, $ } = Lightview;
tags.FileInput = FileInput;

const demo = {
    div: {
        style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem',
        children: [
            { FileInput: {} },
            { FileInput: { label: 'Upload Document', helper: 'PDF, DOC, or DOCX files only', accept: '.pdf,.doc,.docx' } },
            { FileInput: { label: 'Upload Images', accept: 'image/*', multiple: true, color: 'primary', helper: 'You can select multiple images' } },
            { FileInput: { label: 'Resume', required: true, accept: '.pdf' } }
        ]
    }
};

$('#example').content(demo);

Reactive Example

File validation and state display

const { default: FileInput } = await import('/components/data-input/file-input.js');
const { signal, tags, $ } = Lightview;
const { div, p, span, ul, li } = tags;

const selectedFiles = signal([]);

const validateFile = (files) => {
    if (!files || files.length === 0) return 'Please select a file';
    for (const file of files) {
        if (file.size > 5 * 1024 * 1024) {
            return `File "${file.name}" exceeds 5MB limit`;
        }
    }
    return null;
};

const reactiveDemo = div({ style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem' },
    FileInput({ 
        label: 'Upload Files',
        helper: 'Max 5MB per file',
        multiple: true,
        validate: validateFile,
        onChange: (files) => {
            selectedFiles.value = Array.from(files);
        }
    }),
    div({ class: 'divider' }),
    () => {
        const files = selectedFiles.value;
        if (files.length === 0) {
            return p({ class: 'text-sm opacity-50' }, 'No files selected');
        }
        return div({},
            p({ class: 'text-sm font-semibold mb-2' }, 
                `${files.length} file(s) selected:`
            ),
            ul({ class: 'text-xs font-mono', style: 'display: flex; flex-direction: column; gap: 0.25rem' },
                ...files.map(f => 
                    li({}, 
                        span({ class: 'text-primary' }, f.name),
                        span({ class: 'opacity-50' }, ` (${(f.size / 1024).toFixed(1)} KB)`)
                    )
                )
            )
        );
    }
);

$('#example').content(reactiveDemo);
const { default: FileInput } = await import('/components/data-input/file-input.js');
const { signal, $ } = Lightview;

const selectedFiles = signal([]);

const validateFile = (files) => {
    if (!files || files.length === 0) return 'Please select a file';
    for (const file of files) {
        if (file.size > 5 * 1024 * 1024) {
            return `File "${file.name}" exceeds 5MB limit`;
        }
    }
    return null;
};

const reactiveDemo = {
    tag: 'div',
    attributes: { style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem' },
    children: [
        {
            tag: FileInput,
            attributes: {
                label: 'Upload Files',
                helper: 'Max 5MB per file',
                multiple: true,
                validate: validateFile,
                onChange: (files) => { selectedFiles.value = Array.from(files); }
            }
        },
        { tag: 'div', attributes: { class: 'divider' } },
        () => {
            const files = selectedFiles.value;
            if (files.length === 0) {
                return { tag: 'p', attributes: { class: 'text-sm opacity-50' }, children: ['No files selected'] };
            }
            return {
                tag: 'div',
                children: [
                    {
                        tag: 'p',
                        attributes: { class: 'text-sm font-semibold mb-2' },
                        children: [`${files.length} file(s) selected:`]
                    },
                    {
                        tag: 'ul',
                        attributes: { class: 'text-xs font-mono', style: 'display: flex; flex-direction: column; gap: 0.25rem' },
                        children: files.map(f => ({
                            tag: 'li',
                            children: [
                                { tag: 'span', attributes: { class: 'text-primary' }, children: [f.name] },
                                { tag: 'span', attributes: { class: 'opacity-50' }, children: [` (${(f.size / 1024).toFixed(1)} KB)`] }
                            ]
                        }))
                    }
                ]
            };
        }
    ]
};

$('#example').content(reactiveDemo);
const { default: FileInput } = await import('/components/data-input/file-input.js');
const { signal, tags, $ } = Lightview;
tags.FileInput = FileInput;

const selectedFiles = signal([]);

const validateFile = (files) => {
    if (!files || files.length === 0) return 'Please select a file';
    for (const file of files) {
        if (file.size > 5 * 1024 * 1024) {
            return `File "${file.name}" exceeds 5MB limit`;
        }
    }
    return null;
};

const reactiveDemo = {
    div: {
        style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem',
        children: [
            {
                FileInput: {
                    label: 'Upload Files',
                    helper: 'Max 5MB per file',
                    multiple: true,
                    validate: validateFile,
                    onChange: (files) => { selectedFiles.value = Array.from(files); }
                }
            },
            { div: { class: 'divider' } },
            () => {
                const files = selectedFiles.value;
                if (files.length === 0) {
                    return { p: { class: 'text-sm opacity-50', children: ['No files selected'] } };
                }
                return {
                    div: {
                        children: [
                            { p: { class: 'text-sm font-semibold mb-2', children: [`${files.length} file(s) selected:`] } },
                            {
                                ul: {
                                    class: 'text-xs font-mono', style: 'display: flex; flex-direction: column; gap: 0.25rem',
                                    children: files.map(f => ({
                                        li: {
                                            children: [
                                                { span: { class: 'text-primary', children: [f.name] } },
                                                { span: { class: 'opacity-50', children: [` (${(f.size / 1024).toFixed(1)} KB)`] } }
                                            ]
                                        }
                                    }))
                                }
                            }
                        ]
                    }
                };
            }
        ]
    }
};

$('#example').content(reactiveDemo);

Props

Prop Type Default Description
accept string - Accepted file types (e.g., '.pdf,.doc', 'image/*')
multiple boolean false Allow multiple file selection
label string - Label text displayed above the input
helper string - Helper text displayed below the input
error string | function - Error message or reactive error function
validate function - Validation function: (files) => errorMessage | null
color string - 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error'
size string 'md' 'xs' | 'sm' | 'md' | 'lg'
ghost boolean false Ghost style (no background)
disabled boolean false Disable the file input
required boolean false Mark as required field (shows asterisk)
onChange function - Callback when files selected: (files, event) => void
useShadow boolean * Render in Shadow DOM. *Follows global initComponents() setting

Colors

Sizes

Variants

Ghost

Disabled

With Label (Fieldset Pattern)

Upload Avatar

JPG, PNG, or GIF up to 2MB