React - Implement a file upload component using Mui - reactjs

I am trying to build a file upload component. Earlier I did use <input type="file"> but I have very little space to accomodate the input type and within the litle space, I have to display "Choose file" and the total file path. When I decrease the width, the component display is not too elegant to see.
This was my earlier code:
<label id="licensefile">
LicenseFile
<input
type="file"
name="personalLicense"
className={styles.personallicense}
/>
</label>
My CSS :
.personallicense{
position: absolute;
top: 78px;
left:250px;
width:50px;
padding: 0;
margin:0;
}
input[name="personalLicense"] {
width: 30px;
}
I have been looking for alternate using Mui
I want to build something like this:
import FileUploadOutlined from "#mui/icons-material/FileUploadOutlined";
import TextField from "#mui/material/TextField";
<label >
License
<TextField
variant="standard"
type="text"
InputProps={{
endAdornment: (
<FileUploadOutlined
onClick={() => {
handleUpload();
}}
>
</FileUploadOutlined>
),
}}
/>
</label>
How to invoke the file upload from the Mui thing similar to input type "file"
The total space to accomodate this component is almost 50 to 60 px. I cannot adjust more than that as it is an existing compoenent.

I got answer from other source but posting here for any future references:
<TextField
variant="standard"
type="text"
InputProps={{
endAdornment: (
<IconButton component="label">
<FileUploadOutlined />
<input
styles={{display:"none"}}
type="file"
hidden
onChange={handleUpload}
name="[licenseFile]"
/>
</IconButton>
),
}}
/>

Related

React JS MUI Datepicker strange red border

In my reactJS app, I've setted up some datepicker and everything works good.
In a custom page, i have another datepicker and i see a strange red border around it:
The code is:
<DatePicker
disableFuture
style={{ width: "90%", border: "1px solid black" }}
inputFormat="yyyy-MM-dd"
renderInput={(params) => <TextField fullWidth {...params} />}
value={props.value}
fullWidth
onMouseDown={(e) => e.stopPropagation()}
onChange={(e) =>
props.handleChangeComponentValue(props.id, e.target.value)
}
onBlur={(e) => props.handleBlurComponent(props.id, e.target.value)}
/>
inspecting it with chrome i see that the style comes from
<fieldset aria-hidden="true" class="sc-gKseQn jzeLFY MuiOutlinedInput-notchedOutline-SmBCs dwFpjw MuiOutlinedInput-notchedOutline">
<legend class="sc-iBPTik gOBiIn">
<span class="notranslate">&ZeroWidthSpace;</span>
</legend>
</fieldset>
in particular:
.hiztcv.Mui-error .MuiOutlinedInput-notchedOutline {
border-color: #f44336;
}
I'm not setting any class of it, and that color is not set in my project.
Did i miss something?
I also faced the same issue. When I console.log params coming to the renderInput property, I saw that it has the default property of error:true.
So you can fix it like this:
<DatePicker
...
renderInput={(params) => <TextField {...params} error={false} />}
...
/>

material ui: how to align the Input Label properly

I have the following code for input with inputlable
<FormControl>
<InputLabel htmlFor="my-input">
Photo
</InputLabel>
<input
type="file"
/>
</FormControl>
What I see is
What I want is
I get this using:
<TextField
fullWidth
label="photo"
margin="dense"
accept="image/*"
type="file"
InputLabelProps={{
shrink: true,
}}
/>
So how can get this same effect using the previous code i.e using formcontrol, inputlable etc.
The reason i have to use that intead of textfield is react hook form: materail ui: Textfield: onSubmit, not passing Filelist in the data
Just set shrink property of InputLabel true and add a custom margin:
<FormControl>
<InputLabel shrink={true} htmlFor="my-input">
Photo
</InputLabel>
<input style={{ marginTop: "15px" }} type="file" />
</FormControl>

How to fix an upload icon to a file upload input (material UI)

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:
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:
(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:
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.
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>
</>
),
}}
/>
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();
}
};
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>

MaterialUI Label misplacement on Select component

I have a form displaying inside a modal component with several text inputs and select components but somehow the Select Labels are showing at the top left corner of the form. I followed the solution explained here but I am obtaining the same result. Another problem is that when clicking on one Select the other seems to be linked and show focused. I am not experienced with Material and I have been using it for a couple of days only. I really like it but I am a bit lost here. Also, the Select on the left is not aligned with the Text input.
This is the Dialog/Form code. Disregard the Select onChange event functions
{/* Modal Dialog to add the Form*/}
<Dialog maxWidth="100" open={createOpportunity} onClose={handleDialogClose}>
<DialogTitle align='center' id="form-dialog-title">Add New Opportunity</DialogTitle>
<FormControl className={classes.formMainClass}>
<div className='formDivs'>
<TextField autoFocus margin="dense" id="name" label="Opportunity Name" type="text" fullWidth/>
<TextField margin="dense" id="address" label="Address" type="text" fullWidth/>
<TextField margin="dense" id="city" label="City" type="text" fullWidth/>
<div className='state-zip'>
<InputLabel htmlFor="state">State</InputLabel>
<Select fullWidth inputProps={{id: "state"}} value={value} onChange={event => setValue(event.target.value)}>
<MenuItem value="">Empty Value for First Option</MenuItem>
<MenuItem value="Hey">Hey</MenuItem>
</Select>
<span> </span>
<TextField margin="dense" id="zip" label="Zip" type="text" fullWidth/>
</div>
<TextField margin="dense" id="architect" label="Architect" type="text" fullWidth/>
<TextField margin="dense" id="consultant" label="Consultant" type="text" fullWidth/>
<TextField margin="dense" id="duedate" label="Due date" type="date" fullWidth InputLabelProps={{shrink: true}}/>
</div>
<div className='formDivs'>
<InputLabel htmlFor="manager">Manager</InputLabel>
<Select fullWidth inputProps={{id: "manager"}} value={value} onChange={event => setValue(event.target.value)}>
</Select>
<div className='state-zip'>
<InputLabel htmlFor="status">Status</InputLabel>
<Select fullWidth inputProps={{id: "status"}} value={value} onChange={event => setValue(event.target.value)}>
</Select>
<span> </span>
<InputLabel htmlFor="source">Source</InputLabel>
<Select fullWidth inputProps={{id: "source"}} value={value} onChange={event => setValue(event.target.value)}>
</Select>
</div>
<TextField multiline rows={4} rowsMax={Infinity} margin="dense" id="description" label="Description" type="text" fullWidth/>
<TextField multiline rows={4} rowsMax={Infinity} margin="dense" id="notes" label="Notes" type="text" fullWidth/>
</div>
</FormControl>
<DialogContent>
<DialogContentText>Opportunities text.</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleDialogClose} color="primary">Cancel</Button>
<Button onClick={handleDialogClose} color="primary">Save</Button>
</DialogActions>
</Dialog>
Code for the Styling
.opportunities {
display: flex;
align-content: center;
justify-content: flex-start;
align-items: center;
width: auto;
}
.top-buttons {
margin-top: 15px;
margin-bottom: 0;
width: 90%;
}
.formDivs {
width: 50%;
margin: 1% 3%;
}
.state-zip, .manager {
display: flex;
flex-direction: row;
}
Any advise, comment or suggestion is highly appreciated.
the issue is happening because you're using the FormControl element in the wrong way. This element is used to get extra control/feature/functionality over the individual form input.
So wrap your input elements with FormControl individually if you're planning to use FormControl functionalities and use div or form as a wrapping element instead of FormControl in your current code(form will be better).
Here is a related answer
Here is a working demo with the form tag :

react-bootstrap button on same line as text field

I'm using react-bootstrap, how to keep the button in the same line of my text field?
<FormGroup>
<InputGroup >
<FormControl
type="text"
placeholder="Search for artist"
/>
<InputGroup.Append>
<Button><Octicon name="search"/></Button>
</InputGroup.Append>
</InputGroup>
</FormGroup>
Adding a class to the InputGroup and then on the css write that class as
display: flex;
w3schools.com/css/css3_flexbox.asp

Resources