Reputation: 511
I'm building a webchat with React MUI. For the layout, I'd like to use the Flexbox because the chat input is set to auto grow, and I'd like the messages feed container to be able to auto adjust it's height.
However, I struggle to get the overflow scrollbar to work with flex layout.
overflowY: "auto"
height: '100vh'
I've read answers from 'How can I combine flexbox and vertical scroll in a full-height app?', and 'Scrolling a flexbox with overflowing content', and 'How to make a scrollable container with dynamic height using Flexbox'. Using tricks like setting overflow: 'hidden'
on parents div, or setting minHeight: 0
to the list and feed container. I still can't get it to work. I'm struggle to get the proper scroll behaviour and don't know where I'm missing. Please help!
Here is the Codesandbox: https://codesandbox.io/s/mui-webchat-lsn3tm?file=/demo.js
// ----------------------------------------------------------
const contactLenghth = 10;
const messageLength = 20;
// ----------------------------------------------------------
export default function Chat() {
return (
<main
style={{
height: "100vh",
display: "flex",
flexDirection: "column"
}}
>
<AppBar position="sticky">
<Toolbar>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
LOGO
</Typography>
<Button color="inherit">Login</Button>
</Toolbar>
</AppBar>
<Grid container direction="row" alignItems="stretch" sx={{ flexGrow: 1 }}>
<Grid
item
md={3}
sx={{
display: { xs: "none", sm: "flex" },
flexDirection: "column",
overflowY: "auto",
borderRight: "1px solid lightgrey"
}}
>
<Toolbar>
<Typography variant="h6"> Contacts </Typography>
</Toolbar>
<Divider />
<List>
{[...Array(contactLenghth)].map((n, i) => (
<ListItemButton key={i}>
<ListItem disablePadding>
<ListItemAvatar>
<Avatar />
</ListItemAvatar>
<ListItemText primary={`Contact ${i + 1}`} />
</ListItem>
</ListItemButton>
))}
</List>
</Grid>
<Grid
item
xs={12}
md={9}
sx={{ display: "flex", flexDirection: "column" }}
>
<Toolbar>
<Avatar sx={{ mr: 2 }} />
<ListItemText primary="John Doe" />
</Toolbar>
<Divider />
<Stack
direction="column"
spacing={1}
p={2}
justifyContent="flex-end"
sx={{ flexGrow: 1, overflowY: "auto", height: 0 }}
>
{[...Array(messageLength)].map((n, i) => (
<Stack
key={i}
direction="row-reverse"
spacing={2}
justifyContent="end"
>
<Box
sx={{
px: 2,
py: 1,
maxWidth: "60%",
borderRadius: 20,
bgcolor: "secondary.main",
color: "#fff"
}}
>
<Typography>Test message {i + 1}</Typography>
</Box>
</Stack>
))}
</Stack>
<Stack direction="row" p={2} alignItems="flex-end">
<TextField
placeholder="Message"
fullWidth
multiline
maxRows={5}
sx={{
flexGrow: 1,
borderRadius: 7,
"& fieldset": { borderRadius: 7 }
}}
/>
<Box p={1}>
<IconButton>
<SendIcon />
</IconButton>
</Box>
</Stack>
</Grid>
</Grid>
</main>
);
}
Upvotes: 1
Views: 2813
Reputation: 381
Issue is with property justifyContent="flex-end"
your stack.
<Stack
direction="column"
spacing={1}
p={2}
justifyContent="flex-end"
sx={{ flexGrow: 1, overflowY: "auto", height: 0 }}
>
Solution
You can replace that property with direction="column-reverse"
. Since, it's a chat application. You can use unshift to append messages to starting.
Alternate solution:
You can keep the direction as direction="column"
. Have a JS function which would at regular intervals check that div and scroll the content to bottom
function scrollToBottom(){
var element = document.getElementById("yourDiv");
element.scrollTop = element.scrollHeight;
}
//checking every 1sec
window.setInterval(scrollToBottom, 1000)
Upvotes: 1