jifile
Utilities about file input for the best UX.
Installation
npm install jifile
Examples
All examples were written using Next.js and Tailwind-css.
Stack Mode Example
You can get files from onFileChange. Even if new files selected, it is not reset and keeps accumulating.
'use client';
import { File, FileInput, FileLabel } from 'jifile';
import ExampleBlock from '../ui/example-block';
function StackModeExamplePreview() {
const [files, setFiles] = useState<FileList>();
const fileArray = Array.from(files || []);
return (
<>
<File mode="stack" onFileChange={setFiles} files={files}>
<FileLabel>Select File</FileLabel>
<div className="flex flex-col gap-2">
{fileArray.map((file) => (
<span key={file.name}>{file.name}</span>
))}
</div>
<FileInput hidden />
</File>
</>
);
}
Image Preview Example
You can get preveiw image from file easily
'use client'
import { File, FileInput, FileLabel, getPreviewImage } from 'jifile';
import Image from 'next/image';
import { useState } from 'react';
function ImagePreviewExampleResult() {
const [files, setFiles] = useState<FileList>();
const fileArray = Array.from(files || []);
return (
<>
<File onFileChange={setFiles}>
<FileLabel>Select image files</FileLabel>
<FileInput accept="image/*" hidden multiple />
</File>
<div className="flex gap-4">
{fileArray.map((file) => (
<Image
key={file.name}
width={200}
height={200}
src={getPreviewImage(file)}
alt="image preview"
/>
))}
</div>
</>
);
}
With React Hook Form
Simple example with react-hook-form, using stack mode
'use client';
import { File, FileInput, FileLabel, removeFile } from 'jifile';
import { Controller, useForm } from 'react-hook-form';
function WithReactHookFormExampleResult() {
const { control, watch, setValue, getValues } = useForm<{
files?: FileList;
}>();
const fileArray = Array.from(watch('files') || []);
return (
<>
<Controller
control={control}
name={'files'}
render={({ field }) => (
<File mode="stack" onFileChange={field.onChange} files={field.value}>
<FileLabel>Select files</FileLabel>
<FileInput multiple hidden />
</File>
)}
/>
{fileArray.map((file, index) => (
<div key={file.name} className="flex gap-2">
<div>{file.name}</div>
<button
className="bg-red-100 size-5 rounded"
onClick={() => {
const files = getValues('files');
if (!files) return;
const removed = removeFile(files, { index });
setValue('files', removed);
}}
>
x
</button>
</div>
))}
</>
);
}