Skip to content

Instantly share code, notes, and snippets.

@Sqvall
Last active September 19, 2024 18:36
Show Gist options
  • Save Sqvall/23043a12a7fabf0f055198cb6ec39531 to your computer and use it in GitHub Desktop.
Save Sqvall/23043a12a7fabf0f055198cb6ec39531 to your computer and use it in GitHub Desktop.
File Upload with Chakra UI and react-hook-form
import { ReactNode, useRef } from 'react'
import { Button, FormControl, FormErrorMessage, FormLabel, Icon, InputGroup } from '@chakra-ui/react'
import { useForm, UseFormRegisterReturn } from 'react-hook-form'
import { FiFile } from 'react-icons/fi'
type FileUploadProps = {
register: UseFormRegisterReturn
accept?: string
multiple?: boolean
children?: ReactNode
}
const FileUpload = (props: FileUploadProps) => {
const { register, accept, multiple, children } = props
const inputRef = useRef<HTMLInputElement | null>(null)
const { ref, ...rest } = register as {ref: (instance: HTMLInputElement | null) => void}
const handleClick = () => inputRef.current?.click()
return (
<InputGroup onClick={handleClick}>
<input
type={'file'}
multiple={multiple || false}
hidden
accept={accept}
{...rest}
ref={(e) => {
ref(e)
inputRef.current = e
}}
/>
<>
{children}
</>
</InputGroup>
)
}
type FormValues = {
file_: FileList
}
const App = () => {
const { register, handleSubmit, formState: { errors } } = useForm<FormValues>()
const onSubmit = handleSubmit((data) => console.log('On Submit: ', data))
const validateFiles = (value: FileList) => {
if (value.length < 1) {
return 'Files is required'
}
for (const file of Array.from(value)) {
const fsMb = file.size / (1024 * 1024)
const MAX_FILE_SIZE = 10
if (fsMb > MAX_FILE_SIZE) {
return 'Max file size 10mb'
}
}
return true
}
return (
<>
<form onSubmit={onSubmit}>
<FormControl isInvalid={!!errors.file_} isRequired>
<FormLabel>{'File input'}</FormLabel>
<FileUpload
accept={'image/*'}
multiple
register={register('file_', { validate: validateFiles })}
>
<Button leftIcon={<Icon as={FiFile} />}>
Upload
</Button>
</FileUpload>
<FormErrorMessage>
{errors.file_ && errors?.file_.message}
</FormErrorMessage>
</FormControl>
<button>Submit</button>
</form>
</>
)
}
export default App
@Sqvall
Copy link
Author

Sqvall commented Aug 23, 2021

you sir are the goat

What do you mean man?

@jackHedaya
Copy link

Great work! Is there a way to make the upload reactive though? I think because refs are being used the state of the form does not trigger a rerender on change.

@goudarziha
Copy link

you sir are the goat

What do you mean man?

I mean to say Thank you for this, you are the Greatest Of All Time :)

@Sqvall
Copy link
Author

Sqvall commented Sep 29, 2021

you sir are the goat

What do you mean man?

I mean to say Thank you for this, you are the Greatest Of All Time :)

Thanks man, didn't know this phrases before :)

@azharali
Copy link

azharali commented Feb 6, 2022

This is exactly the combination (file-upload with typescript, chakra-ui, react) I've been looking for. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment