Reputation: 163
I have an input of type file that needs to be customized. I need to add an icon in the input button, change the button's name and finally hide the selected file's name. I tried different methods like using a <div>
or <a>
but the problem is that I need to transfer the selected file to json format. So invoking the browsing action via JavaScript is causing an error in conversion. I need to use a customizable input of type file
<input type="file"/>
How I need it to look
Upvotes: 4
Views: 15479
Reputation: 1
To avoid the need to add an id to every input, you can create this reusable component:
import {
DetailedHTMLProps,
FC,
InputHTMLAttributes,
useRef,
} from "react";
export const FileInput: FC<
Omit<
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
"ref"
>
> = ({ children, className, ...props }) => {
const fileInputRef = useRef<HTMLInputElement | null>(null);
return (
<button
onClick={() => {
fileInputRef?.current?.click();
}}
className={className}
>
<input ref={fileInputRef} style={{ display: "none" }} {...props} />
{children}
</button>
);
};
This is how you use it
<FileInput
onChange={(e) => console.log(e)}
className={"bg-blue-950 rounded border"}
>
Style here as you like
</FileInput>
Upvotes: 0
Reputation: 847
Using the HTML label
tag and htmlFor
property is the best solution for this.
Step 1: Create a generic component to provide you with the functionality of file input.
// UploadControl.js
const UploadControl = ({ children, value, onChange, disabled, accept }) => {
return (
<label htmlFor="contained-button-file" className="m-0 w-100">
<input
value={value}
accept={accept}
disabled={disabled}
style={{ display: 'none' }}
id="contained-button-file"
multiple
type="file"
onChange={disabled ? () => {} : onChange}
/>
{children}
</label>
);
};
Step 2: Use this component by wrapping your custom-styled UI.
<button className="btn-styles">
<UploadControl onChange={handleAddBanner} accept="image/*">
Add New Banner
</UploadControl>
</button>
Step 3: Implement a handler to get your file.
const handleAddBanner = ({ target: { files } }) => {
const loadedImage = files[0];
// loadedImage will be a image file.
};
Upvotes: 6
Reputation: 1848
You can achieve this with label and hiding the input.You need to of course style it properly and write a handleFile function.
<div>
<label onChange={handleFile} htmlFor="formId">
<input name="" type="file" id="formId" hidden />
<Icon>
</label>
</div>
Upvotes: 10