Material UI - How can I style the scrollbar with CSS in JS?
Asked Answered
S

14

51

I really hate having to have an external stylesheet for my scrollbar stylings and I want to put it in with the rest of my styles on my root component. I have tried this...

const styles = (theme: Theme) =>
  createStyles({
    scrollBar: {
      '&::-webkit-scrollbar': {
        width: '0.4em'
      },
      '&::-webkit-scrollbar-track': {
        '-webkit-box-shadow': 'inset 0 0 6px rgba(0,0,0,0.00)'
      },
      '&::-webkit-scrollbar-thumb': {
        backgroundColor: 'rgba(0,0,0,.1)',
        outline: '1px solid slategrey'
      }
    }
  });

and then adding the class to root component div. I am using the withStyles HOC and the other styles there are being applied, so I know it is working, but I cannot figure out how to get at the scroll bar styles. Is there any way to do this?

<div className={classes.scrollBar} />
Servais answered 14/12, 2018 at 1:35 Comment(5)
Is the question about the css? Or the technique to do something programmatically?Coercive
the question is about how to do it in JSS. I know the css worksServais
It's just not at all clear to me what you're trying to achieve. Normally CSS classes are defined during development and applied/removed programmatically. What is it you are trying to do?Coercive
Im trying to apply these styles through JSS because the rest of my styles are JSS. I don't want to have css fragmented in different places throughout my code base. I can apply these styles with an imported stylesheet but I cannot figure out how to achieve them through JSSServais
Ahh, so your issue is more with the JSS than anything. I use SASS, so I can't help there. :(Coercive
K
54

Since you want to do this globally, you may want to follow what CssBaseline does in it source code: https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/CssBaseline/CssBaseline.js

const styles = theme => ({
  '@global': {
    '*::-webkit-scrollbar': {
      width: '0.4em'
    },
    '*::-webkit-scrollbar-track': {
      '-webkit-box-shadow': 'inset 0 0 6px rgba(0,0,0,0.00)'
    },
    '*::-webkit-scrollbar-thumb': {
      backgroundColor: 'rgba(0,0,0,.1)',
      outline: '1px solid slategrey'
    }
  }
});

it looks like the top-level/global selector to use is @global.

Knew answered 14/12, 2018 at 22:45 Comment(7)
I actually just discovered this too and was coming back here to write my own answer. Although I had to change the & to * in order for it to work. Can you please change your answer to use * and I will accept it. Thanks!Servais
yeah that makes sense, the & was from the CssBaseline.js (which also makes sense in their case)Knew
how can i hide the scroll only for a single component? I tried changing global with my selector name & putting the code directly inside the selector. But failed with both.Levee
Remove outline: 1px solid slategrey for better look, and also for safari.Composer
sir i am looking for the exact same problem but in am confused how can to integrate scrollbar class with the rest of the code can you pls explain thisHiginbotham
what does & and * mean?Conte
the link of github has 404, also putting this code to my theme.js didnt fix my problem. im using material 4 and nextjsArroyo
I
44

I would recommend to apply scrollbar styles only for the specific container, cause @Global may take rendering time to apply on the All elements. This works fine as for me

list: {
  overflowY: "auto",
  margin: 0,
  padding: 0,
  listStyle: "none",
  height: "100%",
  '&::-webkit-scrollbar': {
    width: '0.4em'
  },
  '&::-webkit-scrollbar-track': {
    boxShadow: 'inset 0 0 6px rgba(0,0,0,0.00)',
    webkitBoxShadow: 'inset 0 0 6px rgba(0,0,0,0.00)'
  },
  '&::-webkit-scrollbar-thumb': {
    backgroundColor: 'rgba(0,0,0,.1)',
    outline: '1px solid slategrey'
  }
}
Invar answered 27/11, 2019 at 8:51 Comment(1)
Everything is right here, except for the space between & and ::.Amongst
T
39

None of the previous 4 answers gives a simple copy/paste solution that works right away for Material UI v4 or v5 and CssBaseline. So heres mine

For v4:

import { createTheme } from "@material-ui/core/styles";

const theme = createTheme({
  overrides: {
    MuiCssBaseline: {
      "@global": {
        body: {
          scrollbarColor: "#6b6b6b #2b2b2b",
          "&::-webkit-scrollbar, & *::-webkit-scrollbar": {
            backgroundColor: "#2b2b2b",
          },
          "&::-webkit-scrollbar-thumb, & *::-webkit-scrollbar-thumb": {
            borderRadius: 8,
            backgroundColor: "#6b6b6b",
            minHeight: 24,
            border: "3px solid #2b2b2b",
          },
          "&::-webkit-scrollbar-thumb:focus, & *::-webkit-scrollbar-thumb:focus": {
            backgroundColor: "#959595",
          },
          "&::-webkit-scrollbar-thumb:active, & *::-webkit-scrollbar-thumb:active": {
            backgroundColor: "#959595",
          },
          "&::-webkit-scrollbar-thumb:hover, & *::-webkit-scrollbar-thumb:hover": {
            backgroundColor: "#959595",
          },
          "&::-webkit-scrollbar-corner, & *::-webkit-scrollbar-corner": {
            backgroundColor: "#2b2b2b",
          },
        },
      },
    },
  },
});

export default theme;

So, If you are using CssBaseline at the top of your app, then just put the overrides object into your global theme and it will work fine.

If you got your hands on the v5 of mui, then use this in your global theme:

// optional for better type support
import type {} from "@mui/lab/themeAugmentation";

import { createTheme } from "@mui/material/styles";

const theme = createTheme({
  components: {
    MuiCssBaseline: {
      styleOverrides: {
        body: {
          scrollbarColor: "#6b6b6b #2b2b2b",
          "&::-webkit-scrollbar, & *::-webkit-scrollbar": {
            backgroundColor: "#2b2b2b",
          },
          "&::-webkit-scrollbar-thumb, & *::-webkit-scrollbar-thumb": {
            borderRadius: 8,
            backgroundColor: "#6b6b6b",
            minHeight: 24,
            border: "3px solid #2b2b2b",
          },
          "&::-webkit-scrollbar-thumb:focus, & *::-webkit-scrollbar-thumb:focus": {
            backgroundColor: "#959595",
          },
          "&::-webkit-scrollbar-thumb:active, & *::-webkit-scrollbar-thumb:active": {
            backgroundColor: "#959595",
          },
          "&::-webkit-scrollbar-thumb:hover, & *::-webkit-scrollbar-thumb:hover": {
            backgroundColor: "#959595",
          },
          "&::-webkit-scrollbar-corner, & *::-webkit-scrollbar-corner": {
            backgroundColor: "#2b2b2b",
          },
        },
      },
    },
  },
});

Transliterate answered 30/8, 2021 at 11:33 Comment(4)
Just copy and pasted for v5, worked perfectly with 0 issues.Mulhouse
'&::-webkit-scrollbar' is working for me but thumb and track are not working, why is it so? :(Conte
great, you saved my time. , your solution is 100% working without any changeGarlic
For some reason, It works fine on FireFox but for Chrome It works only If the devTools are opened on the mobile simulationInevitable
P
16

For me I just wanted to change the scrollbar settings globally, so based on the sample provided here: typography-html-font-size

You can use some approach like this for building your theme:

createMuiTheme({
  overrides: {
    MuiCssBaseline: {
      '@global': {
        '*': {
          'scrollbar-width': 'thin',
        },
        '*::-webkit-scrollbar': {
          width: '4px',
          height: '4px',
        }
      }
    }
  }
})

Then just pass the created object to ThemeProvider. ThemeProvider document

Prittleprattle answered 2/8, 2019 at 11:31 Comment(0)
B
14

In Material UI v5 for the specific element you can simply use:

<Box sx={{
  overflow:"auto",
  scrollbarWidth: 'thin',
  '&::-webkit-scrollbar': {
    width: '0.4em',
  },
  '&::-webkit-scrollbar-track': {
    background: "#f1f1f1",
  },
  '&::-webkit-scrollbar-thumb': {
    backgroundColor: '#888',
  },
  '&::-webkit-scrollbar-thumb:hover': {
    background: '#555'
  }
  }}>
</Box>
Baht answered 16/4, 2022 at 12:15 Comment(3)
I have tried this way because I need a custom scrollbar on a specific element, but this approach didn't work. Any advice?Anyway
@LeleMabur Which MUI version are you using?Baht
It's latest mui, v5.13.6. I have created a question here https://mcmap.net/q/354445/-styling-scrollbar-on-specific-element-on-mui-v5/12291670Anyway
M
9

The simplest one is to use the following code in your app.css file and import it to your App.js :

::-webkit-scrollbar {
  width: 5px;
}

/* Track */
::-webkit-scrollbar-track {
  background: #f1f1f1;
}

/* Handle */
::-webkit-scrollbar-thumb {
  background: #888;
}

/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
  background: #555;
}
Mogul answered 24/1, 2021 at 7:14 Comment(0)
H
6

Update March 2022

In MUI@5 the easiest way the achieve scroll adjusted to dark/light theme is to use Color Scheme in CssBaseline which works in Chrome, Edge & FF

https://mui.com/components/css-baseline/#color-scheme

<CssBaseline enableColorScheme />

CSB for thin scroller for light/dark mode for Chrome, Edge, FF & Safari:

https://codesandbox.io/s/material-ui-toggle-dark-light-mode-scrollbar-t542f7?file=/demo.tsx

More details:

if you want nice thin scroll you can use scroll-width: "thin"

https://caniuse.com/mdn-css_properties_scrollbar-width

but for now in works only in FF

darkScrollbar from MUI makes nice thin dark scrollbar in Edge & Chrome, but not in FF

darkScrollbar has also 3 available options, so we can combine those two methods and pass grey colors for light mode:

import { grey } from "@mui/material/colors";
import { darkScrollbar } from "@mui/material";
...

MuiCssBaseline: {
    styleOverrides: {
      html: {
        ...darkScrollbar(
          mode === "light"
            ? {
                track: grey[200],
                thumb: grey[400],
                active: grey[400],
              }
            : undefined
        ),
        //scrollbarWidth for Firefox
        scrollbarWidth: "thin",
      },
    },
},
Heteropolar answered 2/3, 2022 at 12:19 Comment(0)
D
5

You don't even need to use createTheme, just use GlobalStyles in MUI v5, this is more reusable:

<GlobalStyles
  styles={{
    '*::-webkit-scrollbar': {
      width: '0.4em',
    },
    '*::-webkit-scrollbar-track': {
      '-webkit-box-shadow': 'inset 0 0 6px rgba(0,0,0,0.00)',
    },
    '*::-webkit-scrollbar-thumb': {
      backgroundColor: 'rgba(0,0,0,.1)',
      outline: '1px solid slategrey',
    },
  }}
/>

Or if you want to use a scrollbar in dark theme, MUI has one for you out-of-the-box:

import darkScrollbar from '@mui/material/darkScrollbar';
<GlobalStyles styles={{ ...darkScrollbar() }} />

Live Demo

Codesandbox Demo

Discourse answered 5/11, 2021 at 5:23 Comment(1)
This is the easiest solution and the best one yet for my use case, Thanks.Edmee
H
4

This worked for me in MUI v5

global theme override

...

MuiCssBaseline: {
      styleOverrides: {
        html: {
          '& ::-webkit-scrollbar': {
                            width: '20px',
          },
          '& ::-webkit-scrollbar-track': {
           
          },
          '& ::-webkit-scrollbar-thumb': {
            
          },
          '& ::-webkit-scrollbar-thumb:hover': {
            
          },
        },
      },
    },

...

global specific component override

...

MuiCard: {
      styleOverrides: {
        root: {
          '::-webkit-scrollbar': {
                width: '20px',            
          },
          '::-webkit-scrollbar-button': {
           
          },
          '::-webkit-scrollbar-thumb': {
           
          },
          '::-webkit-scrollbar-thumb:hover': {
          
          },
          '::-webkit-scrollbar-track': {
         
          },
          '::-webkit-scrollbar-track-piece': {
   
          },
          '::-webkit-scrollbar-corner': {
 
          },
          '::-webkit-resizer': {

          },
        },
      },
    },

...

in sx props

...

          <Box
            component="div"
            sx={{
              overflowY: 'scroll',
              height: { xs: '300px' },              
              '::-webkit-scrollbar': {
                width: '20px',
              },
              '::-webkit-scrollbar-button': {
      
              },
              '::-webkit-scrollbar-thumb': {
        
              },
              '::-webkit-scrollbar-thumb:hover': {
                
              },
              '::-webkit-scrollbar-track': {
             
              },
              '::-webkit-scrollbar-track-piece': {
               
              },
              '::-webkit-scrollbar-corner': {
              
              },
              '::-webkit-resizer': {
                
              },
            }}
          >

...

Haemophilic answered 1/8, 2022 at 20:42 Comment(0)
G
2
    const useStyles = makeStyles((theme) => ({
     
    
        DetailedCard: {
            height: theme.spacing(60),
            display: 'flex',
            flexDirection: 'column',
            overflow: 'scroll',
            '&::-webkit-scrollbar': {
             width:0.5px
            },
           '&::-webkit-scrollbar-thumb': {
               width:0.5px
            },
        },
    }))
Garek answered 5/12, 2021 at 11:0 Comment(5)
'&::-webkit-scrollbar' is working for me but thumb and track are not workingConte
use '&::-webkit-scrollbar-thumb' under webkit scrollbarGarek
you mean below it or inside? what if I am not using webkit scrollbar and only need to change the thumb and track color?Conte
i added in the above codeGarek
it works after your suggestion but then the default arrows that come with scrollbar are gone. and it looks horrible without it. tried other solutions for arrows, but they are too much work for a too little thingConte
B
1

joining @Artem Luzhanovskyi, you can show the scroll bar after the hover on parent element that is to keep the design of your element more clean

sx={
    {
        ...
        '&:hover::-webkit-scrollbar': {
        display: 'block',
        },
        '&::-webkit-scrollbar': {
        display: 'none',
        width: '0.512rem',
        },
        '&::-webkit-scrollbar-track': {
        boxShadow: 'inset 0 0 6px rgba(0,0,0,0.00)',
        webkitBoxShadow: 'inset 0 0 6px rgba(0,0,0,0.00)',
        },
        '&::-webkit-scrollbar-thumb': {
        backgroundColor: '#8d8e90',
        height: '8px',
        borderRadius: '8px',
        },
        ...
    }
}

Basion answered 18/10, 2022 at 18:2 Comment(0)
O
0

This configuration works well for Material UI v4 on modern Chrome and Firefox browsers.

const theme = createTheme({
  overrides: {
    MuiCssBaseline: {
      '@global': {
        '*': {
          scrollbarWidth: 'thin',
          scrollbarColor: '#B7B7B7 transparent',
          '&::-webkit-scrollbar': {
            width: 6,
            height: 6,
            backgroundColor: 'transparent',
          },
          '&::-webkit-scrollbar-track': {
            backgroundColor: 'transparent',
          },
          '&::-webkit-scrollbar-thumb': {
            borderRadius: 6,
            backgroundColor: '#B7B7B7',
            minHeight: 24,
            minWidth: 24,
          },
          '&::-webkit-scrollbar-thumb:focus': {
            backgroundColor: '#adadad',
          },
          '&::-webkit-scrollbar-thumb:active': {
            backgroundColor: '#adadad',
          },
          '&::-webkit-scrollbar-thumb:hover': {
            backgroundColor: '#adadad',
          },
          '&::-webkit-scrollbar-corner': {
            backgroundColor: 'transparent',
          },
        },
      },
    },
  },
});
Orthocephalic answered 20/10, 2021 at 10:46 Comment(0)
O
0
import React, { useEffect, useRef, useState } from "react";
import OutlinedInput from "@mui/material/OutlinedInput";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import ListItemText from "@mui/material/ListItemText";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import Checkbox from "@mui/material/Checkbox";
const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
square: true,
elevation: 1,
sx: {
  "&::-webkit-scrollbar": {
    width: 2,
  },
  "&::-webkit-scrollbar-track": {
    boxShadow: `inset 0 0 1px rgba(0, 0, 0, 0.3)`,
  },
  "&::-webkit-scrollbar-thumb": {
    backgroundColor: "darkgrey",
    outline: `1px solid slategrey`,
  },
},
style: {
  maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
  width: 250,
 },
 },
};
const names = [
 "Oliver Hansen",
 "Van Henry",
 "April Tucker",
 "Ralph Hubbard",
 "Omar Alexander",
 "Carlos Abbott",
 "Miriam Wagner",
 "Bradley Wilkerson",
 "Virginia Andrews",
 "Kelly Snyder",
];

const Component= () => {
const [personName, setPersonName] = useState([]);

const handleChange = (event) => {
 const {
  target: { value },
} = event;
setPersonName(
  // On autofill we get a stringified value.
  typeof value === "string" ? value.split(",") : value
);
};
return (
<div
  className="max-h-screen "

>
 
  <div>
    <FormControl sx={{ width: 280 }}>
      <Select
        labelId="demo-multiple-checkbox-labeaaal"
        id="demo-multiple-checkbox66"
        multiple
        value={personName}
        onChange={handleChange}
        placeholder="select style"
        input={<OutlinedInput size="small" sx={{ borderRadius: "8px" }} />}
        renderValue={(selected) => {
          if (selected.length === 0) {
            return <em>Placeholder</em>;
          }

          return selected.join(", ");
        }}
        displayEmpty
        MenuProps={MenuProps}
        // inputProps={{ "aria-label": "Without label" }}
        sx={{
          "&::-webkit-scrollbar": {
            width: 1,
          },
          "&::-webkit-scrollbar-track": {
            boxShadow: `inset 0 0 1px rgba(0, 0, 0, 0.3)`,
          },
          "&::-webkit-scrollbar-thumb": {
            backgroundColor: "darkgrey",
            outline: `1px solid slategrey`,
          },
        }}
      >
        {names.map((name) => (
          <MenuItem
            key={name}
            value={name}
            sx={{
              padding: "0px",
              fontFamily: "Inter",
              fontStyle: "normal",
              fontWeight: "400",
              fontSize: "14px",
              lineHeight: "20px",
            }}
          >
            <Checkbox
              size="small"
              checked={personName.indexOf(name) > -1}
            />
            <ListItemText primary={name} />
          </MenuItem>
        ))}
      </Select>
    </FormControl>
  </div>
</div>
 );
};

export default Component;
Owner answered 27/11, 2022 at 16:19 Comment(0)
S
0
const theme = createTheme({
  overrides: {
    MuiCssBaseline: {
      '@global': {
        '*': {
          scrollbarWidth: 'thin',
          scrollbarColor: '#B7B7B7 transparent',
          '&::-webkit-scrollbar': {
            width: 6,
            height: 6,
            backgroundColor: 'transparent',
          },
          '&::-webkit-scrollbar-track': {
            backgroundColor: 'transparent',
          },
          '&::-webkit-scrollbar-thumb': {
            borderRadius: 6,
            backgroundColor: '#B7B7B7',
            minHeight: 24,
            minWidth: 24,
          },
          '&::-webkit-scrollbar-thumb:focus': {
            backgroundColor: '#adadad',
          },
          '&::-webkit-scrollbar-thumb:active': {
            backgroundColor: '#adadad',
          },
          '&::-webkit-scrollbar-thumb:hover': {
            backgroundColor: '#adadad',
          },
          '&::-webkit-scrollbar-corner': {
            backgroundColor: 'transparent',
          },
        },
      },
    },
  },
});
Sylviesylvite answered 14/12, 2023 at 9:11 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Irreligion

© 2022 - 2024 — McMap. All rights reserved.