I am creating a simple form to upload file using electron-react-boilerplate with redux form & material ui.
The problem is that I do not know how to create input file field because material ui does not support upload file input.
Any ideas on how to achieve this?
This question is related to
reactjs
electron
react-redux
redux-form
formsy-material-ui
You can use Material UI's Input and InputLabel components. Here's an example if you were using them to input spreadsheet files.
import { Input, InputLabel } from "@material-ui/core";
const styles = {
hidden: {
display: "none",
},
importLabel: {
color: "black",
},
};
<InputLabel htmlFor="import-button" style={styles.importLabel}>
<Input
id="import-button"
inputProps={{
accept:
".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel",
}}
onChange={onInputChange}
style={styles.hidden}
type="file"
/>
Import Spreadsheet
</InputLabel>
If you're using React function components, and you don't like to work with labels or IDs, you can also use a reference.
const uploadInputRef = useRef(null);
return (
<Fragment>
<input
ref={uploadInputRef}
type="file"
accept="image/*"
style={{ display: "none" }}
onChange={onChange}
/>
<Button
onClick={() => uploadInputRef.current && uploadInputRef.current.click()}
variant="contained"
>
Upload
</Button>
</Fragment>
);
<input type="file"
id="fileUploadButton"
style={{ display: 'none' }}
onChange={onFileChange}
/>
<label htmlFor={'fileUploadButton'}>
<Button
color="secondary"
className={classes.btnUpload}
variant="contained"
component="span"
startIcon={
<SvgIcon fontSize="small">
<UploadIcon />
</SvgIcon>
}
>
Upload
</Button>
</label>
Make sure Button has component="span", that helped me.
It is work for me ("@material-ui/core": "^4.3.1"):
<Fragment>
<input
color="primary"
accept="image/*"
type="file"
onChange={onChange}
id="icon-button-file"
style={{ display: 'none', }}
/>
<label htmlFor="icon-button-file">
<Button
variant="contained"
component="span"
className={classes.button}
size="large"
color="primary"
>
<ImageIcon className={classes.extendedIcon} />
</Button>
</label>
</Fragment>
Here's an example using an IconButton to capture input (photo/video capture) using v3.9.2:
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import PhotoCamera from '@material-ui/icons/PhotoCamera';
import Videocam from '@material-ui/icons/Videocam';
const styles = (theme) => ({
input: {
display: 'none'
}
});
class MediaCapture extends Component {
static propTypes = {
classes: PropTypes.object.isRequired
};
state: {
images: [],
videos: []
};
handleCapture = ({ target }) => {
const fileReader = new FileReader();
const name = target.accept.includes('image') ? 'images' : 'videos';
fileReader.readAsDataURL(target.files[0]);
fileReader.onload = (e) => {
this.setState((prevState) => ({
[name]: [...prevState[name], e.target.result]
}));
};
};
render() {
const { classes } = this.props;
return (
<Fragment>
<input
accept="image/*"
className={classes.input}
id="icon-button-photo"
onChange={this.handleCapture}
type="file"
/>
<label htmlFor="icon-button-photo">
<IconButton color="primary" component="span">
<PhotoCamera />
</IconButton>
</label>
<input
accept="video/*"
capture="camcorder"
className={classes.input}
id="icon-button-video"
onChange={this.handleCapture}
type="file"
/>
<label htmlFor="icon-button-video">
<IconButton color="primary" component="span">
<Videocam />
</IconButton>
</label>
</Fragment>
);
}
}
export default withStyles(styles, { withTheme: true })(MediaCapture);
Just the same as what should be but change the button component to be label like so
<form id='uploadForm'
action='http://localhost:8000/upload'
method='post'
encType="multipart/form-data">
<input type="file" id="sampleFile" style="display: none;" />
<Button htmlFor="sampleFile" component="label" type={'submit'}>Upload</Button>
</form>
Nov 2020
With Material-UI and React Hooks
import * as React from "react";
import {
Button,
IconButton,
Tooltip,
makeStyles,
Theme,
} from "@material-ui/core";
import { PhotoCamera } from "@material-ui/icons";
const useStyles = makeStyles((theme: Theme) => ({
root: {
"& > *": {
margin: theme.spacing(1),
},
},
input: {
display: "none",
},
faceImage: {
color: theme.palette.primary.light,
},
}));
interface FormProps {
saveFace: any; //(fileName:Blob) => Promise<void>, // callback taking a string and then dispatching a store actions
}
export const FaceForm: React.FunctionComponent<FormProps> = ({ saveFace }) => {
const classes = useStyles();
const [selectedFile, setSelectedFile] = React.useState(null);
const handleCapture = ({ target }: any) => {
setSelectedFile(target.files[0]);
};
const handleSubmit = () => {
saveFace(selectedFile);
};
return (
<>
<input
accept="image/jpeg"
className={classes.input}
id="faceImage"
type="file"
onChange={handleCapture}
/>
<Tooltip title="Select Image">
<label htmlFor="faceImage">
<IconButton
className={classes.faceImage}
color="primary"
aria-label="upload picture"
component="span"
>
<PhotoCamera fontSize="large" />
</IconButton>
</label>
</Tooltip>
<label>{selectedFile ? selectedFile.name : "Select Image"}</label>. . .
<Button onClick={() => handleSubmit()} color="primary">
Save
</Button>
</>
);
};
Here an example:
return (
<Box alignItems='center' display='flex' justifyContent='center' flexDirection='column'>
<Box>
<input accept="image/*" id="upload-company-logo" type='file' hidden />
<label htmlFor="upload-company-logo">
<Button component="span" >
<Paper elevation={5}>
<Avatar src={formik.values.logo} className={classes.avatar} variant='rounded' />
</Paper>
</Button>
</label>
</Box>
</Box>
)
newer MUI version:
<input
accept="image/*"
className={classes.input}
style={{ display: 'none' }}
id="raised-button-file"
multiple
type="file"
/>
<label htmlFor="raised-button-file">
<Button variant="raised" component="span" className={classes.button}>
Upload
</Button>
</label>
You need to wrap your input with component, and add containerElement property with value 'label' ...
<RaisedButton
containerElement='label' // <-- Just add me!
label='My Label'>
<input type="file" />
</RaisedButton>
You can read more about it in this GitHub issue.
EDIT: Update 2019.
Check at the bottom answer from @galki
TLDR;
<input
accept="image/*"
className={classes.input}
style={{ display: 'none' }}
id="raised-button-file"
multiple
type="file"
/>
<label htmlFor="raised-button-file">
<Button variant="raised" component="span" className={classes.button}>
Upload
</Button>
</label>
Source: Stackoverflow.com