How can i make an avatar chooser with Material UI - reactjs

I'm using Material UI v3 within a react project (react v15.6).
What i did so far?
In the sign up page i can get an image from the user to use as his/her profile photo.
What i want to do
I would like to have a shade on the avatar photo to show him that is clickable. like this image...
avatarChooserImage
Someone can tell me, how can i do such a thing? I have no clue. I tried to use plain CSS, but much effort for nothing.

You can do something simple like this,
<IconButton>
<Avatar
src="/images/example.jpg"
style={{
margin: "10px",
width: "60px",
height: "60px",
}}
/>
</IconButton>
Which allow you to have a clickable avatar.
But since you are using it as file input too, maybe you can do something like this,
<input
accept="image/*"
className={classes.input}
id="contained-button-file"
multiple
type="file"
/>
<label htmlFor="contained-button-file">
<IconButton>
<Avatar
src="/images/example.jpg"
style={{
margin: "10px",
width: "60px",
height: "60px",
}}
/>
</IconButton>
</label>
To do an overlay for "edit", have a look at css image overlay. This explains how to place a layer on top on Avatar Icon, it should answer you question.
P.S Accept this as the right answer if it answers your question, thank you.

There's a similar example of this in the documentation:
https://material-ui.com/components/buttons/#upload-button
Instead of using "PhotoCamera" , you can use "Avatar". Allowing you to click on your avatar to upload an image like this for example:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
const useStyles = makeStyles((theme) => ({
root: {
alignSelf: 'center',
justifyContent: "center",
alignItems: "center",
display: 'flex',
'& > *': {
margin: theme.spacing(1),
},
},
input: {
display: "none",
},
large: {
width: theme.spacing(7),
height: theme.spacing(7),
},
}));
export default function ProfileAvatar() {
const classes = useStyles();
return (
<div className={classes.root}>
<input accept="image/*" className={classes.input} id="icon-button-file" type="file" />
<label htmlFor="icon-button-file">
<IconButton color="primary" aria-label="upload picture" component="span">
<Avatar src="https://www.w3schools.com/howto/img_avatar.png" className={classes.large} />
</IconButton>
</label>
</div>
);
}

An hidden input that accepts images only,
and an IconButton with component="span" property, surrounded by the input's label:
<input accept="image/*" id="upload-avatar-pic" type="file" hidden />
<label htmlFor="upload-avatar-pic">
<IconButton component="span">
<Avatar />
</IconButton>
</label>

Related

Using Material-ui for creating an inline form with label,text, select and button elements (similar to Boostrap)

I am struggling to create an inline form using Material-UI and React which resembles the following
Bootstrap HTML snippet
I created the above using the HTML snippet below. You can try this out at W3Schools.
<div class="container">
<h2>Inline form</h2>
<p>Make the viewport larger than 768px wide to see that all of the form elements are inline, left aligned, and the labels are alongside.</p>
<form class="form-inline" action="/action_page.php">
<div class="form-group">
<label for="sel1">Select search field:</label>
<select class="form-control" id="sel1">
<option>FirstName</option>
<option>LastName</option>
<option>PostCode</option>
<option>Gender</option>
</select>
</div>
<div class="form-group">
<input type="email" class="form-control" id="email" placeholder="Enter search pattern" name="email">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
My attempt using Material-ui
<label htmlFor="selectsearchfield">Select search fields</label>
<span> </span>
<NativeSelect id="selectsearchfield" value={{}}>
<option value="FirstName">FirstName</option>
<option value="LastName">LastName</option>
</NativeSelect>
<span> </span>
<TextField
label="" id="outlined-size-small" defaultValue="" variant="outlined" size="small" disableUnderline />
<span> </span>
<Button size="medium" variant="contained" color="primary">Search</Button>
Question
It can be clearly seen that the output from Bootstrap is far more professional.
Please, any suggestions on how to improve the inline form using Material UI look n feel so that it comes close to Bootstrap.
Thank you,
Sau
You can make use of material-ui makeStyles and make it responsive also:-
import React, { useState } from "react";
import "./style.css";
import classNames from "classnames";
import { makeStyles } from "#material-ui/core/styles";
import {
Button,
FormControl,
OutlinedInput,
TextField,
Typography,
Select,
MenuItem
} from "#material-ui/core";
export default function App() {
const classes = useStyles();
const fields = ["FirstName", "LastName", "PostCode", "Gender"];
const [searcBy, setSearchBy] = useState("FirstName");
const [searchText, setSearchText] = useState("");
return (
<div className={classes.root}>
<form className={classes.form}>
<FormControl className={classNames(classes.formControl, classes.text)}>
<Typography variant="body1" className={classes.type}>
Select search fields:
</Typography>
</FormControl>
<FormControl
className={classNames(classes.formControl, classes.select)}
>
<Select
labelId="typesLabel"
label="Types"
input={<OutlinedInput classes={{ input: classes.input }} />}
value={searcBy}
onChange={e => setSearchBy(e.target.value)}
>
{fields.map(field => (
<MenuItem key={field} value={field}>
{field}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl
className={classNames(classes.formControl, classes.search)}
>
<TextField
label="Enter search pattern"
variant="outlined"
size="small"
value={searchText}
onChange={e => setSearchText(e.target.value)}
/>
</FormControl>
<Button
type="submit"
variant="contained"
color="primary"
className={classes.submitBtn}
>
Primary
</Button>
</form>
</div>
);
}
const useStyles = makeStyles(theme => ({
root: {
display: "flex",
justifyContent: "center",
alignItems: "center"
},
form: {
width: 800,
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
alignItems: "center"
},
container: {
display: "flex",
justifyContent: "center",
alignItems: "center"
},
text: {
minWidth: 120
},
type: {
fontWeight: 600
},
formControl: {
marginRight: theme.spacing(1),
[theme.breakpoints.down("xs")]: {
minWidth: "100%",
marginRight: theme.spacing(0),
marginBottom: theme.spacing(1)
}
},
input: {
padding: "10px 14px"
},
select: {
maxWidth: 130
},
search: {
maxWidth: 180
},
submitBtn: {
[theme.breakpoints.down("xs")]: {
width: "100%"
}
}
}));
Or you can also incorporate the use of Grid from #material-ui/core.Grid instead of using 'flex' like the above example.
Here is the result:-
a bit of explanation of what happened above:-
having input={<OutlinedInput classes={{ input: classes.input }} />} as select element props will enable us to create our own outline instead of depending on the given example code from material-ui select documentation code.
the reason why we do this is since you want to make it exactly as you did with Bootstraps example above. We need to somehow make the select element tad shorter in height. With element TextField, you can just specify size="small". But for select, that option is not available. That's why we have this approach. Or you can directly change the select input element overall styles with withStyles of material-ui/core/styles.
You can also refer to this sandbox code to see the actual working result.

How to give Typography-like style to an input element with Material-ui?

I would like my Typography field to become editable, so I transform it into an input.
Now I would like this input to have the same style.
How to do it?
I tried copying the produced css to the input, but it is tedious and seemed not perfect.
Here is a code sandbox to illustrate: https://codesandbox.io/s/flamboyant-stonebraker-le1eq?file=/index.js
I found a workaround for you, but keep in mind that this is not ideal because if you change the current Typography component you have to find its classes again in the chrome devtools, and also the typography with the diaplay: none is necessary for material to render the styles...
import React from "react";
import ReactDOM from "react-dom";
import { Button, InputBase, TextField, Typography } from "#material-ui/core";
function App() {
const [isEditing, setIsEditing] = React.useState(false);
const [value, setValue] = React.useState("Edit me");
const toggleIsEditing = () => setIsEditing((b) => !b);
if (isEditing) {
return (
<div style={{ display: "flex", alignItems: "center" }}>
<input
className="MuiTypography-root MuiTypography-h4 MuiTypography-displayInline"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<Typography style={{ display: "none" }} />
<Button size="small" onClick={toggleIsEditing}>
Done
</Button>
</div>
);
}
return (
<div style={{ display: "flex", alignItems: "center" }}>
<Typography variant="h4" display="inline">
{value}
</Typography>
<Button size="small" onClick={toggleIsEditing}>
Edit
</Button>
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#app"));
<Typography suppressContentEditableWarning={true} contentEditable={true} className={text} onChange={handleChange}>
Some text
</Typography>
Css (to prevent the nasty looking border, when you click into the Typography):
text: {
outline: `0 solid transparent`,
}

How do I set a width for the TextAreaAutoSize component in Material-UI?

I can't find any info anywhere on how to change the default width of a TextAreaAutosize component in material-ui.
It seems the only choice is to have this little box. Does anyone know of a better text area auto size component I can use, or how to change the width of the TextAreaAutoSize component?
The API doesn't show any properties that have anything to do with 'className'. I tried to use it anyway and it was ignored. I also tried wrapping the component in a Box, and styling that, but it was ignored by the TextArea.
Any help would be greatly appreciated!
Resizing by the user is turned off (via resize: "none") for TextField here in InputBase: https://github.com/mui-org/material-ui/blob/v4.10.2/packages/material-ui/src/InputBase/InputBase.js#L140.
Below is an example of how to turn it back on:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles(theme => ({
root: {
"& .MuiTextField-root": {
margin: theme.spacing(1)
}
},
textarea: {
resize: "both"
}
}));
export default function MultilineTextFields() {
const classes = useStyles();
return (
<form className={classes.root} noValidate autoComplete="off">
<div>
<TextField
id="outlined-textarea"
label="Multiline Placeholder"
placeholder="Placeholder"
multiline
variant="outlined"
inputProps={{ className: classes.textarea }}
/>
</div>
</form>
);
}
CSS documentation for resize: https://developer.mozilla.org/en-US/docs/Web/CSS/resize
Multiline TextField demos: https://material-ui.com/components/text-fields/#multiline
You can change the style prop of the TextareaAutosize check here
<TextareaAutosize
rowsMin={3}
placeholder=''
defaultValue=''
style={{ width: "100%" }}
/>
I was able to get it to work thanks to Ryan Cogswell. Stupid me, though I wrapped the textarea in a box and applied className to the box (which didn't work), I should have applied it to the textareaautosize directly.
There's a bug in VSCODE Intellisense where it shows 'classes' as a property but not 'className' so I assumed it didn't exist.
Here's the code:
const FormStyles = makeStyles((theme) => ({
root: {
width: '100%',
},
button: {
marginTop: '20px',
marginRight: theme.spacing(1),
},
buttons: {
display: 'flex',
justifyContent: 'flex-end'
},
textarea: {
width: '100%',
},
}));
<TextareaAutosize
rowsMin={3}
aria-label={info.label}
name={info.name}
placeholder=''
defaultValue=''
className={classes.textarea}
/>
I could not get the drag icon to show up in textfield, so didn't use it. But I would appreciate an example of textfield using multiline and resizing.
Thanks Ryan!
Here's the trick I used. I wrapped it in a flex container and used align-items to stretch the width to cover the size of that container.
<Stack
direction="column"
justifyContent="center"
alignItems="stretch"
spacing={2}
>
<TextareaAutosize
label='Title'
value={pub.title || ''}
onChange={(e) => pub.title = e.target.value}
variant='outlined'
sx={{m: 1}}
size='small'
/>
</Stack>

React - jss nested Sass-like styling is not working

I have an application where I am using Material-UI v.3 as a UI framework. I have a label with button that has display: none as the default state, that I would like to show on hover over the parent element.
I have made a simple codesandbox here of the relevant parts. The jsx code looks like this:
<div className={classes.volumeWrapper}>
<VolumeUpIcon />
<input
accept="image/*"
className={classes.fileInput}
id="contained-button-file"
multiple
type="file"
/>
<label htmlFor="contained-button-file">
<Button
variant="contained"
component="span"
className={classes.fileButton}
>
<AddIcon />
</Button>
</label>
</div>
And the styling for it is this:
fileInput: {
display: "none"
},
volumeWrapper: {
"& label": {
display: "none"
},
"& :hover": {
"& label": {
display: "block"
}
}
}
Why is this not working, and what am I doing wrong here?

Is there a way to create a button with a linear progress within it, using material-ui?

I want to create a button with a built-in linear progress bar. something like this experience, but with Material components:
https://demo.tutorialzine.com/2013/10/buttons-built-in-progress-meters/
I know that there's a way to integrate <CircularProgress/> into a button, is there a way to integrate <LinearProgress/>? it didn't work for me.
Thanks in advance.
Much like the CircularProgress example, which I presume you are referring to this, it's just about getting the CSS correct.
I've forked that example and added a button that has LinearProgress integrated to give you an idea, the relevant code for that example is:
linearProgress: {
position: "absolute",
top: 0,
width: "100%",
height: "100%",
opacity: 0.4,
borderRadius: 4
}
...
<div className={classes.wrapper}>
<Button
variant="contained"
color="primary"
className={buttonClassname}
disabled={loading}
onClick={handleButtonClick}
>
Linear
</Button>
{loading && (
<LinearProgress
color="secondary"
className={classes.linearProgress}
/>
)}
</div>
Something like this:
import React from 'react'
import { makeStyles } from '#material-ui/core/styles'
import Button from '#material-ui/core/Button'
import LinearProgress from '#material-ui/core/LinearProgress'
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
},
button: {
margin: theme.spacing(1),
},
}))
export default function ContainedButtons() {
const classes = useStyles()
return (
<div className={classes.root}>
<Button variant="contained" className={classes.button}>
<div>
Demo
<LinearProgress variant="determinate" value={75} />
</div>
</Button>
</div>
)
}

Resources