40

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} />
Olivier Tassinari
  • 8,238
  • 4
  • 23
  • 23
Joff
  • 11,247
  • 16
  • 60
  • 103
  • Is the question about the css? Or the technique to do something programmatically? – theMayer Dec 14 '18 at 02:01
  • the question is about how to do it in JSS. I know the css works – Joff Dec 14 '18 at 02:18
  • 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? – theMayer Dec 14 '18 at 15:30
  • 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 JSS – Joff Dec 14 '18 at 17:25
  • Ahh, so your issue is more with the JSS than anything. I use SASS, so I can't help there. :( – theMayer Dec 14 '18 at 18:11

13 Answers13

52

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.

  • 2
    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! – Joff Dec 15 '18 at 03:20
  • yeah that makes sense, the & was from the CssBaseline.js (which also makes sense in their case) –  Dec 15 '18 at 04:40
  • 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. – Mohammed Amir Ansari Sep 18 '19 at 11:14
  • Remove `outline: 1px solid slategrey` for better look, and also for safari. – glinda93 Dec 31 '20 at 11:35
  • 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 this – Ali Raza Apr 01 '21 at 09:13
  • what does & and * mean? – Vipin Verma Feb 23 '22 at 20:43
  • 1
    the link of github has 404, also putting this code to my theme.js didnt fix my problem. im using material 4 and nextjs – Evaa Dec 05 '22 at 16:51
39

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'
  }
}
Artem Luzhanovskyi
  • 1,767
  • 1
  • 11
  • 8
25

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 beta 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",
          },
        },
      },
    },
  },
});

Olivier Tassinari
  • 8,238
  • 4
  • 23
  • 23
fathomless
  • 392
  • 6
  • 12
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

user487779
  • 550
  • 5
  • 12
Naeem Baghi
  • 811
  • 2
  • 14
  • 29
9

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>
Olivier Tassinari
  • 8,238
  • 4
  • 23
  • 23
Abdul Rehman
  • 139
  • 1
  • 5
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

NearHuscarl
  • 66,950
  • 18
  • 261
  • 230
4

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;
}
Tina
  • 464
  • 4
  • 11
4

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",
      },
    },
},
keemor
  • 1,149
  • 15
  • 16
3

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': {
                
              },
            }}
          >

...

atazmin
  • 4,757
  • 1
  • 32
  • 23
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
            },
        },
    }))
Shahnad S
  • 983
  • 10
  • 17
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',
        },
        ...
    }
}

DINA TAKLIT
  • 7,074
  • 10
  • 69
  • 74
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',
          },
        },
      },
    },
  },
});
Burak Özdemir
  • 510
  • 8
  • 18
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;