samchuang
samchuang

Reputation: 511

How to get overflow scrollbar on flexbox layout

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.

  1. When I set message length at 20, the message feed overflows above the container, and I can't get the scrollbar even when I have overflowY: "auto"

enter image description here

  1. When I set contacts length to 20, it pushes down the content down, even when I set the root container to height: '100vh'

enter image description here

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

Answers (1)

Singh3y
Singh3y

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

Related Questions