2

I'm currently trying to build a file upload Input field with an icon as an input adornment, using Material UI. I want to be able to click the icon to upload a file.

Following the MUI documentation here: input adornment, I have tried to follow the exact formatting except using an IconButton instead of the Password visibility icon in the demo.

Here is a sample of my code:

   <FormControl className={classes.formControl}>
      <InputLabel htmlFor="upload-script">Sim Script</InputLabel>
      <Input
        id="upload-script"
        type="file"
        value={values.script}
        onChange={() => handleChange('script')}
        endAdornment={
          <InputAdornment position="end">
            <IconButton aria-label="upload">
              <PublishIcon />                        // (here is my icon)
            </IconButton>
          </InputAdornment>
        }
      />
    </FormControl>

This works, but the result is not at all what I was intending- here is a screenshot of what it looks like in the browser: upload field

You can see my upload icon all the way on the right, but the input field clearly has its own upload button and placeholder text ('No file chosen').

Looking online, I saw a suggestion here: (similar StackOverflow post) that says we should add style: {{ display: none }} to the Input component, and add component="span" as a property of the IconButton. When I try this, however, this is what the browser gives us:

upload field pt2

(this is all the way scrolled... my sources icon is gone, the Input field has no line delimiter underneath, the spacing is clearly messed up...)

Clearly, neither of these is what I want haha. Can anyone help?? (I hope this description is good enough...)

Thank you so much!!

-

EDIT: Here is what it looks like with @Shiladitya's initial solution: pt3

But I want there to be a line for the text field! I want it to look exactly like the 'Sim Binary' text field, except with an upload icon on the right instead of a dropdown arrow.

tprebenda
  • 389
  • 1
  • 6
  • 17

3 Answers3

2

I've recently returned and edited my component, which was inspired by @Shiladitya but now uses a better system that I somehow missed before:

<TextField
  className={classes.formControl}
  id={`sim-script-${sim.uuid}`}
  label="Sim Script- click the Upload Icon"
  required
  inputRef={scriptInputRef}     // To focus on the field after clicking icon
  value={sim.script}
  InputProps={{
    readOnly: true,
    endAdornment: (
      <>
        <AdjustedTooltip title="Upload script" arrow>
          <IconButton
            aria-label="upload"
            className={classes.uploadIcon}
            component="label"             // THIS IS THE GENIUS CHANGE
          >
            <PublishIcon />
            <input
              hidden
              type="file"
              onChange={(e) => scriptUpload(e)}
            />
          </IconButton>
        </AdjustedTooltip>
      </>
    ),
  }}
/>

This way, we can remove all the input and label wrappers, and instead just set the Material UI Button to have the attribute component="label", with the input tag inside the icon button.

Also here is my onChange/scriptUpload function, in case people are interested:

const scriptUpload = (e: ChangeEvent<HTMLInputElement>) => {
  // the first/only file selected by user
  if (e.target.files?.item(0)) {  
    onChange(sim.uuid, "script", e.target.files?.item(0)!.name);
  }

  // Focus textfield
  if (scriptInputRef.current) {
    scriptInputRef.current.focus();
  }
};
Dharman
  • 30,962
  • 25
  • 85
  • 135
tprebenda
  • 389
  • 1
  • 6
  • 17
1

Here you go with a solution

const handleFileUpload = () => {}
<>
  <input
    style={{
      display: "none"
    }}
    accept=".json"  // specify the file type that you wanted to accept
    id="choose-file"
    type="file"
    onChange={handleFileUpload}
  />
  <label htmlFor="choose-file">
    <IconButton aria-label="upload">
      <PublishIcon />
    </IconButton>
  </label>
</>

EDIT with Textfield

     <TextField
        className={classes.margin}
        id="input-with-icon-textfield"
        label="TextField"
        InputProps={{
          endAdornment: (
            <>
              <input
                style={{
                  display: "none"
                }}
                accept=".json"
                id="choose-file"
                type="file"
                onChange={handleFileUpload}
              />
              <label htmlFor="choose-file">
                <IconButton aria-label="upload">
                  <PublishIcon />
                </IconButton>
              </label>
            </>
          ),
        }}
      />
Shiladitya
  • 12,003
  • 15
  • 25
  • 38
0

Another Solution.

* {
  margin: 0 auto;
  font-family: Helvetica;
}
html {
  background-color: #e9e9e9;
}

#choose-file {
  display: none;
}

#wrapper {
  display: inline-flex;
  justify-content: center;
  margin-left: 20px;
  background-color: orange;
  width: 60px;
  align-items: center;
  cursor: pointer;
}
<form>
  <label id="first">
   Sim Binary
  <div id="wrapper">
  <input
    accept=".json"
    id="choose-file"
    type="file"
  />
     ⇪
  </div>
     </label>
</form>
Filipe Prado
  • 126
  • 4