Material UI make 2 elements the same height - css

I have the following code:
<div className="center">
<TextField
variant="outlined"
className="manualUserFollowTxt"
required
id="manualUserFollowTxt"
label="Username"
name="username"
autoComplete="username"
autoFocus
/>
<Button variant="contained" color="primary" className="manualUserFollowButton"
onClick={(e) => this.followButtonClick(e, document.getElementById("manualUserFollowTxt").value)}
>
Follow
</Button>
</div>
Which basically results in:
what I have
What I want is to have the TextField and the Button be the same height with a little space in between and sitting on one line, preferably in the middle. Something like:
what I want
How can I achieve this??

In order to make the TextField and Button the same height and aligned, you can CSS Flexbox on the parent div.
Set the display to flex, and flex-direction to row.
In order to apply spacing between the TextField and Button, you can apply margin-right to the TextField (here I used material-ui styling):
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
const useStyles = makeStyles(theme => ({
textField: {
marginRight: theme.spacing(2),
},
}));
export default function TextFieldDemo() {
const classes = useStyles();
return (
<div style={{display: 'flex', flexDirection: 'row'}}>
<TextField
variant="outlined"
className={classes.textField}
required
id="manualUserFollowTxt"
label="Username"
name="username"
autoComplete="username"
autoFocus
/>
<Button variant="contained" color="primary" className="manualUserFollowButton"
onClick={(e) => this.followButtonClick(e, document.getElementById("manualUserFollowTxt").value)}
>
Follow
</Button>
</div>
);
}

Related

Material-UI: Expand Accordion by clicking the icon only

I have created an Accordion for my Project. But I want the panel to be expanded only when the expand icon is clicked. Currently it is expanding on clicking anywhere on the panel. Can we customize its expanding behavior ?
CODE:
import React from "react";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
import Accordion from "#material-ui/core/Accordion";
import AccordionDetails from "#material-ui/core/AccordionDetails";
import Typography from "#material-ui/core/Typography";
import AccordionSummary from "#material-ui/core/AccordionSummary";
export default function App() {
return (
<div style={{}}>
<h4>How to create Accordion in ReactJS?</h4>
<Accordion style={{ width: 400}}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
>
<div>Click to Expand</div>
</AccordionSummary>
<AccordionDetails>
<Typography>Greetings of the day :)</Typography>
</AccordionDetails>
</Accordion>
</div>
);
}
Yes we can do it like this
1- Create our own state with handler:
const [expand, setExpand] = React.useState(false);
const toggleAcordion = () => {
setExpand((prev) => !prev);
};
2- Add our state to the Accordion:
<Accordion expanded={expand} style={{ width: 400 }}>
3- Add onClick for the icon:
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
IconButtonProps={{
onClick: toggleAcordion
}}
>
Full Code:
EDIT: Explanation: Material-UI Accordion has its own state (open or close) and its own click handler, what we did above is that we create our own state and override Material-UI Accordion state by the prop expanded and add event listener onClick to the icon button by the prop IconButtonProps, our event listener will open or close the Accordion by change our state.
NOTE: The code above doesn't change the style in case of the cursor pointer.
There is no public API to do what you want out-of-the-box, but you can use this CSS trick:
V5
<AccordionSummary
sx={{
pointerEvents: "none"
}}
expandIcon={
<ExpandMoreIcon
sx={{
pointerEvents: "auto"
}}
/>
}
>
V4
const useStyles = makeStyles({
summary: {
pointerEvents: 'none',
},
icon: {
pointerEvents: 'auto',
},
});
<AccordionSummary
className={classes.summary}
expandIcon={<ExpandMoreIcon className={classes.icon} />}
>
<Typography>Accordion 1</Typography>
</AccordionSummary>
Live Demo
For v5, and setting the mouse cursor properly:
1- Create our own state with handler:
const [accordionOpen, setAccordionOpen] = React.useState(false);
2- Add our state to the Accordion and toggle on click:
<Accordion expanded={accordionOpen}>
<AccordionSummary
expandIcon={
<ExpandMoreIcon
style={{ cursor: 'pointer' }}
onClick={() => setAccordionOpen(!accordionOpen)} />
}
sx={{ cursor: 'unset !important' }}
>
None of these solutions worked for me. I handled it with the e.stopPropagation() method, using it in the onClick event of the icon after calling the toggle function.
Like this:
import React from "react";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
import Accordion from "#material-ui/core/Accordion";
import AccordionDetails from "#material-ui/core/AccordionDetails";
import Typography from "#material-ui/core/Typography";
import AccordionSummary from "#material-ui/core/AccordionSummary";
export default function App() {
return (
<div style={{}}>
<h4>How to create Accordion in ReactJS?</h4>
<Accordion style={{ width: 400}}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
>
<div ><img src='yourIcon' onClick={(e) => { toggleAccordion(); e.stopPropagation() }} /></div>
</AccordionSummary>
<AccordionDetails>
<Typography>Greetings of the day :)</Typography>
</AccordionDetails>
</Accordion>
</div>
);
}
you can try set expanded true/false in the Accordion
function Container(props) {
const [expand, setExpand] = React.useState(false);
const toggleAccordion = () => {
setExpand((prev) => !prev);
};
return (
<React.Fragment>
<Accordion expanded={expand}>
<AccordionSummary
expandIcon={<ExpandMoreIcon
onClick={toggleAccordion}
/>}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography></Typography>
</AccordionSummary>
<AccordionDetails>
</AccordionDetails>
</Accordion>
</React.Fragment>)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Align icon inside Material UI Button

How to insert an icon centering material ui button?
Piece of Code:
<Button variant="outlined" startIcon={<Add color='primary'/>} style={{ maxWidth: "36px" }} />
Expected behavior:
Current behavior:
this margin is coming from startIcon class from material-ui itself. To remove this pass a class in to the startIcon in classes prop.
<Button
style={{ maxWidth: "36px", minWidth: "36px" }}
classes={{ startIcon: classes.startICon }}
variant="outlined"
startIcon={<Add />}
></Button>
And add the class in the useStyles to remove the margin.
const useStyles = makeStyles((theme) => ({
startICon: {
margin: 0
}
}));
Here is the working demo:

How to align a Material UI Button and TextField on the same line, at same height?

I'm trying to get a <Button> from the Material UI library to a) sit at same height as the <TextField> next to it; and b) have it be aligned with that same field.
Both the <Button> and the <TextField> are each inside their own <Grid> component (with a container wrapping them).
The container <Grid> has the prop alignItems="center", which produces this result:
It's here I'm running into difficult trying to get the height of the <Button> to match that of the input field. This must be a relatively common requirement - is there a simple way of achieving this?
Given that you have each of your element in a <Grid> component themselves, this should work:
https://codesandbox.io/s/material-ui-playground-forked-1yymw?file=/app.jsx
Use container={true} for Grid to set it as a flex container. Aside from that, you can always leverage makeStyles to generally customize the components' style
MUI Grid container prop
If true, the component will have the flex container behavior.
const useStyles = makeStyles({
fullHeightButton: {
height: "100%"
}
});
function App() {
const classes = useStyles();
return (
<React.Fragment>
<Grid container={true}>
<TextField variant="outlined"/>
<Button variant="contained" color="primary">+</Button>
</Grid>
<br/>
<Grid container={true}>
<Grid><TextField variant="outlined"/></Grid>
<Grid><Button classes={{root: classes.fullHeightButton}} variant="contained" color="primary">+</Button></Grid>
</Grid>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById("test"));
<body>
<div id="test"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/#material-ui/core#latest/umd/material-ui.development.js"></script>
<script type="text/babel">
const { Button, Grid, makeStyles, TextField } = MaterialUI;
</script>
</body>
In my case, I had two buttons that sandwiched a TextField, where the spacing between the first button and the textfield was wrong as shown:
Buttons before code addition
My code was:
<CardActions className='cardactions'>
<Button variant='contained' color='error'> - </Button>
<TextField id='outlined-basic' variant='outlined' size='small' type='number' label='Enter Quantity'/>
<Button variant='contained' color='success'>+</Button>
</CardActions>
Adding sx={{ marginRight:1}} to the first button corrected the issue.
Buttons after code addition
Code after addition:
<CardActions className='cardactions'>
<Button variant='contained' color='error' sx={{ marginRight:1}}> - </Button>
<TextField id='outlined-basic' variant='outlined' size='small' type='number' label='Enter Quantity'/>
<Button variant='contained' color='success'>+</Button>
</CardActions>

Why does this code does not show buttons on different lines instead of side-by-side?

The following code prints Logo then on next line all buttons side-by-side. In the first <div> tag I have tried putting block, inline-block, and removing the display property entirely. Also tried removing the Box mui tag. Nothing works. I am inexperienced in css and maybe making a silly mistake.
Its a nextjs project.
import {makeStyles} from '#material-ui/core/styles';
import DashboardIcon from '#material-ui/icons/DashboardOutlined';
import ListingsIcon from '#material-ui/icons/Reorder';
import ScheduleIcon from '#material-ui/icons/EventNote';
import ProfileIcon from '#material-ui/icons/AccountCircleOutlined';
import SalesIcon from '#material-ui/icons/TrendingUp';
import BookingsIcon from '../../public/images/bookingsIcon.svg';
import Logo from '../mainLogo';
import Box from '#material-ui/core/Box';
const useStyles = makeStyles((theme) => ({
root: {
'& > *': {
margin: theme.spacing(1),
},
},
}));
export default function SideNav() {
const classes = useStyles();
return (
<Box>
<Logo />
<div display="block">
<Button
variant="contained"
color="primary"
className={classes.root}
startIcon={<DashboardIcon />}
>
Dashboard
</Button>
<Button
variant="contained"
color="primary"
className={classes.root}
startIcon={<ListingsIcon />}
>
Listings
</Button>
<Button
variant="contained"
color="primary"
className={classes.root}
startIcon={<ScheduleIcon />}
>
Schedule
</Button>
<Button
variant="contained"
color="primary"
className={classes.root}
startIcon={<BookingsIcon />}
>
Bookings
</Button>
<Button
variant="contained"
color="primary"
className={classes.root}
startIcon={<SalesIcon />}
>
Sales & Analytics
</Button>
<Button
variant="contained"
color="primary"
className={classes.root}
startIcon={<ProfileIcon />}
>
Profile
</Button>
</div>
</Box>
);
};
Can you try putting flex on the div with a direction of column like so:
<div style={{display:'flex', flexDirection:'column'}}>
<Button
variant="contained"
color="primary"
className={classes.root}
startIcon={<DashboardIcon />}
>
Dashboard
</Button>
...
...
...
</div>
Just add the display block on the button itself,
Buttons by default are inline-block elements and div by default is a block-level element so you need to add the display block to the button tag itself instead of the div.
button {
display: block;
}
<button>button 1</button>
<button>button 2</button>
try <div style={{display:"flex"}}>
As #nishkaush said, you should use flex in this case, but since you're also using Material-UI, you can use the Box component which provides some css props for you to quickly prototype the styling of the container.
<Box display="flex" flexDirection="column" gridRowGap={10}>
<Button {...} />
<Button {...} />
...
</Box>
Live Demo

AppBar overlaps with other elements

I am starting to use React/Material-UI, and also new to CSS etc...
I have a simple page layout with an APPBar. Unfortunately this AppBar overlaps the elements which are meant to go below it.
I have found this answer:
AppBar Material UI questions
But this feels completely wrong. What if my AppBar has a variable height, depending on the icons, display modes etc...?
I have tried to create a vertical grid, to wrap the elements in different items, made the top container a flex one and play with flex settings, nothing seems to work, the app bar always sits on top of the text.
The code is very simple:
import React from 'react';
import { AppBar, Typography, Box } from '#material-ui/core';
function App() {
return (
<div>
<AppBar>
<Typography variant='h3'>
AppBar
</Typography>
</AppBar>
<Box>
<Typography variant='h1' style={{ border: '1px solid black' }}>
Hello
</Typography>
</Box>
</div>
)
}
export default App;
The "Hello" text chunk is only half visible:
This is happening because the MaterialUI App Bar defaults to position="fixed". This separates it from the standard DOM's layout to allow content to scroll beneath it, but as a result no space is made for it on the page.
You can get around this by wrapping all content below it in a div and specifying enough margin, or by changing the position property of <AppBar> so it's no longer "fixed". In your example, you could also just apply the styles to <Box> if that's the only content below the <AppBar>.
e.g.
import React from 'react';
import { AppBar, Typography, Box } from '#material-ui/core';
function App() {
return (
<div>
<AppBar>
<Typography variant='h3'>
AppBar
</Typography>
</AppBar>
<div style={{marginTop: 80}}>
<Box>
<Typography variant='h1' style={{ border: '1px solid black' }}>
Hello
</Typography>
</Box>
</div>
</div>
)
}
export default App;
MaterialUI provides a theme mixin for the AppBar that can help. Not sure if you're using the recomended JSS setup, but you can do something like this:
import withStyles from '#material-ui/core/styles/withStyles';
const styles = theme => ({
appBarSpacer: theme.mixins.toolbar
});
const style = withStyles(styles)
function MyScreen ({ classes }) {
<AppBar></AppBar>
<div className={classes.appBarSpacer}></div>
<Box></Box>
}
export default style(MyScreen)
The mixin will give that div the same height as your AppBar, pushing down the other content.
According to Material-ui, there are 3 solutions to this problem.
https://material-ui.com/components/app-bar/#fixed-placement
You can use position="sticky" instead of fixed. ⚠️ sticky is not supported by IE 11.
You can render a second component
You can use theme.mixins.toolbar CSS
I personally enjoy using the 2nd solution like this.
return (
<>
<AppBar position="fixed">
<Toolbar>{/* content */}</Toolbar>
</AppBar>
<Toolbar />
</>
);
<AppBar position='static'>
use this it will do it and content won't hide under Appear
I think having a good app setup is opinianted, but I would recommend the following
import React from "react";
import ReactDOM from "react-dom";
import {
AppBar,
Typography,
Box,
CssBaseline,
makeStyles,
Container,
Grid,
Toolbar
} from "#material-ui/core";
const useStyles = makeStyles(theme => ({
content: {
flexGrow: 1,
height: "100vh",
overflow: "auto"
},
appBarSpacer: theme.mixins.toolbar,
title: {
flexGrow: 1
},
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4)
}
}));
function App() {
const classes = useStyles();
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="absolute">
<Toolbar className={classes.toolbar}>
<Typography
component="h1"
variant="h6"
color="inherit"
noWrap
className={classes.title}
>
AppBar
</Typography>
</Toolbar>
</AppBar>
<main className={classes.content}>
<div className={classes.appBarSpacer} />
<Container maxWidth="lg" className={classes.container}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Box>
<Typography variant="h1" style={{ border: "1px solid black" }}>
Hello
</Typography>
</Box>
</Grid>
</Grid>
</Container>
</main>
</div>
);
}
try this!
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
[theme.breakpoints.down('sm')]: {
marginBottom: 56,
},
[theme.breakpoints.up('sm')]: {
marginBottom: 64,
},
},
menuButton: {
marginRight: theme.spacing(1),
},
title: {
flexGrow: 1,
}, }))
You can add the above to your code like this
const Navbar = () => {
const classes = useStyles()
return (
<div className={classes.root}>
<AppBar position='fixed' color='primary'>
<Toolbar>
<IconButton
edge='start'
className={classes.menuButton}
color='inherit'
aria-label='menu'>
<MenuIcon />
</IconButton>
<Typography variant='h6' className={classes.title}>
News
</Typography>
<Button color='inherit'>Login</Button>
</Toolbar>
</AppBar>
</div>
)}
For more documentation visit material-ui breakpoint customization

Resources