Material-ui: [FlatButton] File input not working with button.

Created on 15 May 2015  ·  27Comments  ·  Source: mui-org/material-ui

With this...

<FlatButton primary={true} label="Choose an Image">
  <input type="file" id="imageButton"></input>
</FlatButton>

I end up with a button that doesn't actually render a file input field in the dom (clicking on the button does not open up the file dialog).

Most helpful comment

If anyone else comes across this issue I found that you can set containerElement on the RaisedButton to be something more suited to having an input element as a child. For example a label ;-)

<RaisedButton
  containerElement='label' // <-- Just add me!
  label='My Label'>
    <input type="file" />
</RaisedButton>

All 27 comments

On version 0.7.5.

@nschaubeck Does the button on the doc site work for you?

@hai-cea Yes it does. It seemed like there wasn't even an <input> element _in_ DOM, like the button element wasn't rendering it's children.

I'm having this problem as well. @nschaubeck Did you ever find a solution?

@e-monson I was actually not able to find a solution.

this works!
let styles = {
exampleImageInput: {
cursor: 'pointer',
position: 'absolute',
top: '0',
bottom: '0',
right: '0',
left: '0',
width: '100%',
opacity: '0'
}
}

      <FlatButton label="Choose an Image" primary={true}>
        <input id="imageButton" style={styles.exampleImageInput} type="file"></input>
      </FlatButton>

@nikhildaga That only works on Chrome as placing input fields into buttons is not part of the W3C spec.

A different solution is to make the button just fire the click event of a hidden input field.

handleChange: function(e){
  console.log(e.target.value)
},
_openFileDialog: function(){
  var fileUploadDom = React.findDOMNode(this.refs.fileUpload);
  fileUploadDom.click();
},
render: function() {
  return (
    <FlatButton
      label="Upload file"
      onClick={this._openFileDialog}/>
    <input
      ref="fileUpload"
      type="file" 
      style={{"display" : "none"}}
      onChange={this._handleChange}/>
  );
}

I see this issue is still not fixed correctly...
The solution proposed in the doc only works in Chrome as @Wofiel said. (still the case in beta 15-0.2)

Wouldn't it better to be able to set like a htmlFor to the <FlatButton> (or <RaisedButton>), set an Id to the input file and that's all ? You wouldn't need to trigger the click manually...
I tried wrapping the button in the label, unfortunately, that doesn't work :(

Right now @Wofiel seems to be the best solution.

Why close this when there is not a native solution

hi @Wofiel how do you suggest using this technique without refs in a stateless component

@excalliburbd You can use id and Jquery, that should work

@Birssan dom manipulation in react? is that okay?

I would not recommand it usually, but I think to trigger a click event that should be ok in this case

@Wofiel As can be done with version 15 react?

@Wofiel with this solution console.log(e.target.value) one receive
C:\fakepath\imagefilename.png
Best solutions is
e.target.files[0]

If anyone else comes across this issue I found that you can set containerElement on the RaisedButton to be something more suited to having an input element as a child. For example a label ;-)

<RaisedButton
  containerElement='label' // <-- Just add me!
  label='My Label'>
    <input type="file" />
</RaisedButton>

@Thomas101 Thanks! I've just encountered this issue and your solution seems to work.
Awesome :)

@Thomas101 Thanks for the tip. This solved my problem as well. The actual

Just complementing @Thomas101 answer, when I declare the components like his example, my RaisedButton is rendered with a file input inside. To prevent this, just set the file input style to display: none. :)

<RaisedButton
  containerElement='label' // <-- Just add me!
  label='My Label'>
    <input type="file" style={{ display: 'none' }} />
</RaisedButton>

@andreyluiz under what circumstances does this not work:

<RaisedButton label='My Label'>
    <input type="file" />
</RaisedButton>

I haven't been able to find an issue wit the docs site example, but clearly many others have this issue!

Is it suposed to the file input to not show with the code you provided?

That's weird. In my case it renders an file input inside the material-ui button.

@andreyluiz Yes, with the docs site example (http://www.material-ui.com/#/components/raised-button) there's no visible <input>. What browser & version are you testing with?

The latest Chrome version.

I agree with @andreyluiz , the shows as well, but with a style={{display: 'none'}}, it works like a charm !

tl;dr

<RaisedButton
  containerElement="label"
  icon={<Icons.FileUpload />} // material-ui-icons
  labelColor="white"
  primary
  style={{ minWidth: 40, width: 40 }}>
  <input
    onChange={e => this.upload(e.target.files[0])}
    style={{ display: 'none' }}
    type="file"
  />
</RaisedButton>

The above solution doesn't seem to work any more. I'm using the new v1 beta branch and the following doesn't work for me

                        <Button dense
                                containerElement="label"
                                label="label">
                            <input
                                onChange={e => this.upload(e.target.files[0])}
                                style={{display: 'none'}}
                                type="file"
                            />
                        </Button>

I get the following error in the console:

Warning: React does not recognize the `containerElement` prop on a DOM element.
If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `containerelement` instead.
If you accidentally passed it from a parent component, remove it from the DOM element.

Anybody know a workaround? Anyways shouldn't such a common use case be natively supported? (in a non-hacky way)

@AdityaAnand1 the following code should work

<Button
            raised
            component="label" <---- use component instead of containerElement
            color="primary"
            className={buttonClassname}
            disabled={this.state.loading}
            onClick={this.handleButtonClick}
          >
            {'Upload'}
            <FileUpload className={classes.rightIcon} />
            <input
              onChange={e => console.log(e.target.files[0])}
              style={{ display: 'none' }}
              type="file"
            />
</Button>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

mb-copart picture mb-copart  ·  3Comments

ghost picture ghost  ·  3Comments

pola88 picture pola88  ·  3Comments

ryanflorence picture ryanflorence  ·  3Comments

newoga picture newoga  ·  3Comments