Skip to content

Instantly share code, notes, and snippets.

@hbarcelos
Created December 10, 2019 18:31
Show Gist options
  • Select an option

  • Save hbarcelos/e5d5024453a73fc976a5bb80973d58f0 to your computer and use it in GitHub Desktop.

Select an option

Save hbarcelos/e5d5024453a73fc976a5bb80973d58f0 to your computer and use it in GitHub Desktop.
Material UI File Input draft
import React, { useState, useCallback } from 'react';
import t from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Input from '@material-ui/core/Input';
import FormHelperText from '@material-ui/core/FormHelperText';
import AttachmentIcon from '@material-ui/icons/Attachment';
import { toMegaBytes } from '../../format';
const renderFileNames = ({ files }) =>
files.map((file, index) => (
<FormHelperText key={`${file.name}-${index}`}>
{file.name} ({toMegaBytes(file.size)})
</FormHelperText>
));
const useStyles = makeStyles(theme => ({
input: {
display: 'none',
},
buttonLabel: {
maxWidth: 'auto',
},
}));
function FileInput({
label,
id,
multiple,
ButtonProps,
className,
inputProps,
renderHelper,
renderEmptyHelper,
...rest
}) {
const cl = useStyles();
const [files, setFiles] = useState([]);
const handleChange = useCallback(evt => {
setFiles([...evt.target.files]);
}, []);
return (
<React.Fragment>
<Button {...ButtonProps} htmlFor={id} component="label" startIcon={<AttachmentIcon />} className={cl.buttonLabel}>
{label}
</Button>
<Input
{...rest}
id={id}
type="file"
inputProps={{ ...inputProps, multiple }}
className={clsx(className, cl.input)}
onChange={handleChange}
/>
{files.length === 0
? renderEmptyHelper({
id,
multiple,
files,
})
: renderHelper({
id,
multiple,
files,
})}
</React.Fragment>
);
}
FileInput.propTypes = {
label: t.string.isRequired,
id: t.string.isRequired,
multiple: t.bool,
className: t.string,
ButtonProps: t.object,
inputProps: t.object,
renderHelper: t.func,
renderEmptyHelper: t.func,
};
FileInput.defaultProps = {
multiple: false,
className: '',
ButtonProps: {},
inputProps: {},
renderHelper: renderFileNames,
renderEmptyHelper: () => null,
};
export default FileInput;
@hbarcelos

Copy link
Copy Markdown
Author

IMPORTANT:
When using with FormControl, to prevent the button from getting its width increased when selecting files with large filenames, make sure to include:

alignItems: 'flex-start'

to the FormControl styles.

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