React - Material UI Drawer and Header Bar - reactjs

This is my first post, so let me know if I have done anything wrong. I have searched for an answer, and have not been able to find anything on this site or anywhere else. I have started playing around with React to make an intranet application at work. My previous knowledge is mostly .Net and I was only an amateur at that.
For my application I am leveraging the NPM Material UI modules. I am trying to get the Drawer to always be below the header bar and the header bar to move all the way across the screen. Currently, the position of the drawer blocks out part of the header part. My current App.js is as follows
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { withStyles } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
import Drawer from '#material-ui/core/Drawer';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import IconButton from '#material-ui/core/IconButton';
import Badge from '#material-ui/core/Badge';
import ChevronLeftIcon from '#material-ui/icons/ChevronLeft';
import ChevronRightIcon from '#material-ui/icons/ChevronRight';
import NotificationsIcon from '#material-ui/icons/Notifications';
import { mainListItems, secondaryListItems } from './Components/Sidebar.js';
const drawerWidth = 240;
const styles = theme => ({
root: {
display: 'flex',
},
toolbar: {
paddingRight: 24, // keep right padding when drawer closed
},
chevronLeft: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar,
},
chevronRight: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar,
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
appBarShift: {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
chevronRightButton: {
marginLeft: 12,
marginRight: 36,
},
chevronRightButtonHidden: {
display: 'none',
},
chevronLeftButton: {
marginLeft: 12,
marginRight: 36,
},
chevronLeftButtonHidden: {
display: 'none',
},
title: {
flexGrow: 1,
},
drawerPaper: {
position: 'relative',
whiteSpace: 'nowrap',
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
drawerPaperClose: {
overflowX: 'hidden',
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
width: theme.spacing.unit * 7,
[theme.breakpoints.up('sm')]: {
width: theme.spacing.unit * 9,
},
},
appBarSpacer: theme.mixins.toolbar,
content: {
flexGrow: 1,
padding: theme.spacing.unit * 3,
height: '100vh',
overflow: 'auto',
},
chartContainer: {
marginLeft: -22,
},
tableContainer: {
height: 320,
},
});
class Dashboard extends React.Component {
state = {
open: true,
};
handleDrawerOpen = () => {
this.setState({ open: true });
};
handleDrawerClose = () => {
this.setState({ open: false });
};
render() {
const { classes } = this.props;
return (
<React.Fragment>
<CssBaseline />
<div className={classes.root}>
<AppBar
position="absolute"
className={classNames(classes.appBar, this.state.open && classes.appBarShift)}
>
<Toolbar disableGutters={!this.state.open} className={classes.toolbar}>
<Typography variant="title" color="inherit" noWrap className={classes.title}>
Dashboard
</Typography>
<IconButton color="inherit">
<Badge badgeContent={4} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton>
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
classes={{
paper: classNames(classes.drawerPaper, !this.state.open && classes.drawerPaperClose),}}
open={this.state.open}
>
<Divider />
<List>{mainListItems}</List>
<Divider />
<List>{secondaryListItems}</List>
<div className={classes.chevronLeft}>
<IconButton
color="inherit"
aria-label="Close drawer"
onClick={this.handleDrawerClose}
// className={classNames(
// classes.chevronLeftButton,
// this.state.open && classes.chevronLeftButtonHidden,)}
>
<ChevronLeftIcon />
</IconButton>
</div>
<IconButton
color="inherit"
aria-label="Open drawer"
onClick={this.handleDrawerOpen}
className={classNames(
classes.chevronRightButton,
this.state.open && classes.chevronRightButtonHidden,)}
>
<ChevronRightIcon />
</IconButton>
</Drawer>
</div>
</React.Fragment>
);
}
}
Dashboard.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(Dashboard);
You will no doubt notice the Chevrons don't work correctly. Only one is supposed to be visible at a time, but I am still working on that.
Any advice you can give me to correct the appearance would be greatly appreciated.
Thanks in advance.
Regards,
Mitch

Related

MUI default dashboard template, localStorage bug

I'm developing nextjs app. For a start I downloaded this default dashboard theme from MUI website https://mui.com/material-ui/getting-started/templates/dashboard/ code: https://github.com/mui/material-ui/blob/v5.10.13/docs/data/material/getting-started/templates/dashboard/Dashboard.tsx
However, when I try to implement localStorage that will store "open" drawer state like in the snippet bellow it bugs- on refresh it's always in the default state, even if the value in localStorage is set to false (when trying to log the stored value, it is correct). When I try to click the button after the refresh with false value nothing happens because it sets the value to true, only next click takes an effect. Any idea what may cause that bug? According to error: Warning: Prop className did not match. Server: "MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit MuiIconButton-edgeStart MuiIconButton-sizeMedium css-1johsky-MuiButtonBase-root-MuiIconButton-root" Client: "MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit MuiIconButton-edgeStart MuiIconButton-sizeMedium css-dhvns5-MuiButtonBase-root-MuiIconButton-root"
My code:
import * as React from 'react';
import { styled, createTheme, ThemeProvider } from '#mui/material/styles';
import CssBaseline from '#mui/material/CssBaseline';
import MuiDrawer from '#mui/material/Drawer';
import Box from '#mui/material/Box';
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '#mui/material/AppBar';
import Toolbar from '#mui/material/Toolbar';
import List from '#mui/material/List';
import Typography from '#mui/material/Typography';
import Divider from '#mui/material/Divider';
import IconButton from '#mui/material/IconButton';
import Badge from '#mui/material/Badge';
import Container from '#mui/material/Container';
import Grid from '#mui/material/Grid';
import Paper from '#mui/material/Paper';
import Link from '#mui/material/Link';
import MenuIcon from '#mui/icons-material/Menu';
import ChevronLeftIcon from '#mui/icons-material/ChevronLeft';
import NotificationsIcon from '#mui/icons-material/Notifications';
import theme from "../theme";
import { firstListMenu, secondaryListMenu } from './MenuList';
import {useEffect, useState} from "react";
const drawerWidth: number = 200;
interface AppBarProps extends MuiAppBarProps {
open?: boolean;
}
type Props = {
children?: JSX.Element;
}
const AppBar = styled(MuiAppBar, {
shouldForwardProp: (prop) => prop !== 'open',
})<AppBarProps>(({ theme, open }) => ({
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
...(open && {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
}),
}));
const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })(
({ theme, open }) => ({
'& .MuiDrawer-paper': {
position: 'relative',
whiteSpace: 'nowrap',
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
boxSizing: 'border-box',
...(!open && {
overflowX: 'hidden',
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
width: theme.spacing(7),
[theme.breakpoints.up('sm')]: {
width: theme.spacing(9),
},
}),
},
}),
);
const mdTheme = theme;
export default function Layout({children}: Props) {
const [open, setOpen] = useState(() => {
try {
const value = window.localStorage.getItem('open');
if (value) {
return JSON.parse(value);
} else {
window.localStorage.setItem('open', JSON.stringify(true));
return true;
}
} catch (err) {
return true;
}
});
const toggleDrawer = () => {
try {
window.localStorage.setItem('open', JSON.stringify(!open));
} catch (err) {
console.log(err)
}
setOpen(!open);
};
useEffect(() => {
console.log(open)
})
return (
<ThemeProvider theme={mdTheme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="absolute" open={open}>
<Toolbar
sx={{
pr: '24px', // keep right padding when drawer closed
}}
>
<IconButton
edge="start"
color="inherit"
aria-label="open drawer"
onClick={toggleDrawer}
sx={{
marginRight: '36px',
...(open && { display: 'none' }),
}}
>
<MenuIcon />
</IconButton>
<Typography
component="h1"
variant="h6"
color="inherit"
noWrap
sx={{ flexGrow: 1 }}
>
Dashboard
</Typography>
<IconButton color="inherit">
<Badge badgeContent={4} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton>
</Toolbar>
</AppBar>
<Drawer variant="permanent" open={open}>
<Toolbar
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
px: [1],
}}
>
<IconButton onClick={toggleDrawer}>
<ChevronLeftIcon />
</IconButton>
</Toolbar>
<Divider />
<List component="nav">
{firstListMenu}
<Divider sx={{ my: 1 }} />
{secondaryListMenu}
</List>
</Drawer>
<Box
component="main"
sx={{
backgroundColor: (theme) =>
theme.palette.mode === 'light'
? theme.palette.grey[100]
: theme.palette.grey[900],
flexGrow: 1,
height: '100vh',
overflow: 'auto',
}}
>
<Toolbar />
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Grid container spacing={3}>
{/* Chart */}
<Grid item xs={12} md={8} lg={9}>
<Paper
sx={{
p: 2,
display: 'flex',
flexDirection: 'column',
height: 240,
}}
>
{children}
</Paper>
</Grid>
{/* Recent Deposits */}
<Grid item xs={12} md={4} lg={3}>
<Paper
sx={{
p: 2,
display: 'flex',
flexDirection: 'column',
height: 240,
}}
>
</Paper>
</Grid>
{/* Recent Orders */}
<Grid item xs={12}>
<Paper sx={{ p: 2, display: 'flex', flexDirection: 'column' }}>
</Paper>
</Grid>
</Grid>
</Container>
</Box>
</Box>
</ThemeProvider>
);
}
The problem occured because it is rendered on server side. I had to change localStorage to cookies and use getServerSideProps.

Connect React Material UI: Mini Variant + Responsive drawer

I am new to React and Material UI and I've been trying really hard to connect Mini Variant Drawer that I have now with Responsive drawer, so when you use it on phone it changes to Responsive drawer. If anyone could help me it would mean a lot to me, I tried but I always failed.
It would also help me get the knowledge for further connections with drawers.
Here is my code that I use for Mini Variant Drawer:
import React, {useState} from 'react';
import clsx from 'clsx';
import { makeStyles } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
import Drawer from '#material-ui/core/Drawer';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
import MenuOpenIcon from '#material-ui/icons/MenuOpen';
import { MainListItems } from './listItems';
import AccountMenu from '../../components/AccountMenu'
import ChangePasswordDialog from './ChangePasswordDialog';
const drawerWidth = 240;
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
},
toolbar: {
paddingRight: 60,
},
toolbarIcon: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar,
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
appBarShift: {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
menuButton: {
marginRight: 36,
},
menuButtonHidden: {
display: 'none',
},
mainTitle: {
flexGrow: 1,
marginLeft: 12
},
title: {
flexGrow: 1,
},
drawerPaper: {
position: 'relative',
whiteSpace: 'nowrap',
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
drawerPaperClose: {
overflowX: 'hidden',
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
width: theme.spacing.unit * 7,
[theme.breakpoints.up('sm')]: {
width: theme.spacing.unit * 9,
},
},
appBarSpacer: theme.mixins.toolbar,
content: {
flexGrow: 1,
height: '100vh',
overflow: 'auto',
},
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4),
},
paper: {
padding: theme.spacing(2),
display: 'flex',
overflow: 'auto',
flexDirection: 'column',
},
fixedHeight: {
height: 240,
},
}));
export default function SideMenuLayout({
drawerOpen,
setDrawerOpen,
children,
title
}) {
const classes = useStyles();
const handleDrawerOpen = () => {
setDrawerOpen(true);
};
const handleDrawerClose = () => {
setDrawerOpen(false);
};
const [changePasswordDialogOpen, setChangePasswordDialogOpen] = useState(false)
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="absolute" className={clsx(classes.appBar, drawerOpen && classes.appBarShift)}>
<Toolbar className={classes.toolbar}>
<IconButton
edge="start"
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
className={clsx(classes.menuButton, drawerOpen && classes.menuButtonHidden)}
>
<MenuIcon />
</IconButton>
<Typography component="h1" variant="h6" color="inherit" noWrap className={classes.title}>
{drawerOpen ? title : `MyTitle - ${title}`}
</Typography>
<AccountMenu onChangePassword={() => setChangePasswordDialogOpen(true)} />
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
classes={{
paper: clsx(classes.drawerPaper, !drawerOpen && classes.drawerPaperClose),
}}
open={drawerOpen}
>
<div className={classes.toolbarIcon}>
<Typography component="h1" variant="h6" color="inherit" noWrap className={classes.mainTitle}>
MyTitle
</Typography>
<IconButton onClick={handleDrawerClose}>
<MenuOpenIcon />
</IconButton>
</div>
<Divider />
<List><MainListItems /></List>
</Drawer>
<main className={classes.content}>
<div className={classes.appBarSpacer} />
{children}
</main>
<ChangePasswordDialog
isOpen={changePasswordDialogOpen}
setOpen={setChangePasswordDialogOpen}
/>
</div>
);
}
I too have stumbled upon some issue trying to mix together the two drawer variants, but after a couple of hours I've found a configuration that seems to work properly.
NOTE: I'm absolutely no expert in JS/CSS/HTML, I'm way more a backend guy, so this solution can certainly be optimized and modified to fit your needs.
In my case the drawer is used to select the "page" to display. So I'll start from there.
The "page" component simply contains a Router. Its contents are put inside a Box with display: flex:
const HomePage = () => {
return (
<Router>
<Box sx={{display: 'flex'}}>
<HomePageInner />
<Switch>
<Route path="/">
<p>Example</p>
</Route>
</Switch>
</Box>
</Router>
);
}
The HomePageInner is the component that renders the "menu" and appbar.
It keeps tracks of the open/closed status:
const drawerWidth = 240;
const HomePageInner = () => {
const [open, setOpen] = useState(true);
const toggleDrawer = () => setOpen(!open);
const drawer = <DrawerContents onClick={toggleDrawer} />;
return (
<>
<MainAppBar open={open} onClick={toggleDrawer}/>
<Box
component="nav"
aria-label="menu items"
>
<MobileDrawer open={open} onClose={toggleDrawer} drawer={drawer}/>
<DesktopDrawer open={open} drawer={drawer}/>
</Box>
</>
);
}
Here you can see that for clarity I have defined two distinct components for "mobile" and for "desktop". The contents of the drawer are shared and are defined in a separate DrawerContents component that is passed as a child.
There is an outer Box that wraps both Drawers. In the examples on this Box there is an sx property that specifies width: {sm: drawerWidth}, flexShrink: {sm :0}, the flexShrink should be removed, but trying to add/remove the width setting does not seem to do anything, but if something is broken for you try to set that property.
The DrawerContents is pretty simple. It places the "chevron" icon button on the top that can be used to toggle the state and shows the links:
const DrawerContents: FunctionComponent<{ onClick: () => void }> = (props) => {
return <>
<Toolbar
sx={{
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
px: [1],
}}
>
<IconButton onClick={props.onClick}>
<ChevronLeftIcon/>
</IconButton>
</Toolbar>
<Divider/>
<List>
<ListItemLink primary="First" to="/first" icon={<DashboardIcon/>}/>
</List>
<List>
<ListItemLink primary="Second" to="/second" icon={<TodayIcon/>}/>
</List>
<Divider/>
<List>
<ListItemLink primary="Third" to="/third" icon={<SettingsIcon/>}/>
</List>
</>;
}
Now for the interesting part! The Drawers and the AppBar. So, the MobileDrawer is pretty much exactly the same as the temporary drawer in the "Responsive Drawer" example:
const MobileDrawer: FunctionComponent<{ container?: (() => any), open: boolean, onClose: () => void }> = (props) => {
return <Drawer
variant="temporary"
container={props.container}
open={props.open}
onClose={props.onClose}
ModalProps={{
keepMounted: true,
}}
sx={{
display: {xs: "block", sm: "none"},
"& .MuiDrawer-paper": {boxSizing: "border-box", width: drawerWidth},
}}
>
{props.children}
</Drawer>;
}
For the DesktopDrawer is mostly the same of the permanent drawer in th Responsive Drawer example however you have to modify the styling in the sx property so that it changes width when the status changes:
const DesktopDrawer: FunctionComponent<{ open: boolean }> = (props) => {
return <Drawer
variant="permanent"
sx={{
display: {xs: "none", sm: "block"},
"& .MuiDrawer-paper": {
position: "relative",
whiteSpace: "nowrap",
width: drawerWidth,
transition: theme => theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
boxSizing: "border-box",
...(!props.open && {
overflowX: "hidden",
transition: theme => theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
width: theme => ({xs: theme.spacing(7), sm: theme.spacing(9)}),
})
},
}}
open={props.open}
>
{props.children}
</Drawer>;
}
Note that here I made ample use of the function form of the sx properties that gives you access to the theme. I derived the correct values by "mergin" the values I saw in the Mini-Variant example and the Responsive example.
And now the MainAppBar. This too is quite similar to the Responsive Drawer example, however again we have to modify the sx property:
const MainAppBar: FunctionComponent<{ open: boolean, onClick: () => void }> = (props) => {
const location = useLocation();
const headers: { [key: string]: string } = {
'/first': "First",
'/second': "Second",
'/third': "Third",
};
return <AppBar
position="fixed"
sx={{
zIndex: theme => theme.zIndex.drawer + 1,
transition: theme => theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
...(props.open && {
ml: {sm: `${drawerWidth}px`},
width: {sm: `calc(100% - ${drawerWidth}px)`},
transition: theme => theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
})
}}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={props.onClick}
sx={{mr: 2}}
>
<MenuIcon/>
</IconButton>
<Typography
component="h1"
variant="h6"
color="inherit"
noWrap
sx={{flexGrow: 1}}
>
{headers[location.pathname] || "Error"}
</Typography>
</Toolbar>
</AppBar>;
}
Note that here you want to:
remove the display: { sm: 'none' } in the sx of the IconButton to toggle the state
The width and ml settings must be included only in the open state
With all this configuration I get a drawer that for larger screen can be opened/closed like the mini variant:
But is also responsive:
PS: I didn't have the time to write a short answer, so I wrote a long one by copy&pasting my code and cutting away some stuff. If I find some time I might modify the sample code to be shorter and/or be self-contained.

How to change style (Color ; Icon ; Indicator ; Size etc..) Indicator of Tabs with Material-UI ⚛️ React Web?

I implementing TabsBar in my Appbar for my React Desktop Application.
But I really have a hard time stylizing the Tabs part. If anyone can help me with clear explanations, that would be great. I want to add Icons to the right of the text. Change the color of the tab indicator and put it on top as on the picture example. I'm a beginner. I searched for 4 days but the I ask because I block
We have two colors :(#738889) & (#006F85) for actived Tab.
AppBar with Tabs Designed
Voici Mon code actuel ci-dessous :
import React from 'react';
import PropTypes from 'prop-types';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import SearchIcon from '#material-ui/icons/Search';
import InputBase from '#material-ui/core/InputBase';
import Icon from '#material-ui/core/Icon';
import { fade, makeStyles } from '#material-ui/core/styles';
import { withStyles } from '#material-ui/core/styles';
import { ReactComponent as BrandLogo } from '../Assets//PriceWanted/BrandLogo.svg';
import { ReactComponent as Icon_MicroPhone } from '../Icons/Icon_MicroPhone.svg';
import { ReactComponent as Icon_Separation } from '../Icons/Icon_Separation.svg';
import { ReactComponent as Icon_Global } from '../Icons/Icon_Global.svg';
import { ReactComponent as Icon_Lightning } from '../Icons/Icon_Lightning.svg';
import { ReactComponent as Icon_Shipment_Boat } from '../Icons/Icon_Shipment_Boat.svg';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
width: '100%',
backgroundColor: theme.palette.background.paper,
},
Tabs: {
marginLeft: 50,
},
search: {
position: 'relative',
borderRadius: theme.shape.borderRadius,
transition: theme.transitions.create('backgroundColor'),
marginRight: 10,
width: '100%',
backgroundColor: fade(theme.palette.common.black, 0.15),
'&:hover': {
backgroundColor: fade(theme.palette.common.black, 0.70),
boxShadow: '0 3px 5px 2px rgba(25, 1, 12, .2)',
},
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing(3),
width: 'auto',
},
},
inputRoot: {
color: '#2F6164',
'&:hover': {
color: '#b2ebf2',
},
},
inputInput: {
padding: theme.spacing(1),
paddingLeft: `calc(1em + ${theme.spacing(2.5)}px)`,
paddingRight: `calc(1em + ${theme.spacing(2.5)}px)`,
transition: theme.transitions.create('width'),
width: '90%',
flex: 1,
[theme.breakpoints.up('sm')]: {
borderColor: 'grey',
'&:focus': {
borderColor: 'green',
},
width: '35ch',
'&:focus': {
width: '50ch',
},
},
},
searchIcon: {
padding: theme.spacing(0, 1),
color: '#889FA0',
height: '100%',
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
iconButton: {
padding:5,
marginRight: 6,
marginLeft: 6,
},
Toolbar: {
alignItems:'center'
},
}));
TabPanel.propTypes = {children: PropTypes.node,index: PropTypes.any.isRequired,value: PropTypes.any.isRequired,};
function TabPanel(props) {const { children, value, index, ...other } = props;}
function a11yProps(index) {return{id: `simple-tab-${index}`,'aria-controls': `simple-tabpanel-${index}`,};}
export default function SimpleTabs() {
const classes = useStyles();
const StyledButton = withStyles({
root : {background: 'linear-gradient(270deg,#00DBFF 0%, #021118 61.57%, #000000 100%)',
'&:hover': {background:'linear-gradient(90deg, #00DBFF 0%, #000000 100%)',},
position: 'relative',
borderRadius: 4,
border: 1,
color: 'White',
height: 35,
padding: '10 5px',
boxShadow: '0 3px 5px 2px rgba(0px 4px 4px #CBCBCB)',
marginLeft: 1,
justifyContent:'center'},
textTransform: 'capitalize',})(Button);
const [value, setValue] = React.useState(0);
const handleChange = (event,newValue) => {setValue(newValue);};
return (
<div className={classes.grow}>
<AppBar position="static">
<AppBar style={{background: '#FFFFFF'}}>
<Toolbar>
<BrandLogo/>
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase placeholder="Marque,Modèle..."classes={{ root: classes.inputRoot,input: classes.inputInput,}}
inputProps={{ 'aria-label': 'search' }}/>
<IconButton className={classes.iconButton} aria-label="menu">
<Icon_MicroPhone/>
</IconButton>
</div>
<Icon_Separation style={{ flex: 1 }}/>
<Tabs
value={value}
onChange={handleChange}
variant="fullWidth"
indicatorColor="secondary"
textColor="secondary"
aria-label="icon label tabs example">
<Tab label="LIVE DEALS" {...a11yProps(0)} icon={<Icon_Lightning />}/>
<Tab label="GLOBAL STOCK" {...a11yProps(1)} icon={<Icon_Global/>}/>
<Tab label="TRANSPORT" {...a11yProps(2)} icon={<Icon_Shipment_Boat/>}/>
</Tabs>
<StyledButton
variant="contained"
color="primary"
className={classes.StyledButton}
endIcon={<Icon>power_settings_new&style</Icon>}>
CONNEXION
</StyledButton>
</Toolbar>
</AppBar>
</AppBar>
</div>);}
<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>

borderRadius not working when use Material UI

I using ReactJS and Material-UI in my web application. When I define props search for search bar, it's working except borderRadius. I checked Style tab in the Developer Tools (F12), border-radius property was overwritten but search bar not change. Please help me.
My code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from './../actions/index';
import AppBar from '#material-ui/core/AppBar';
import Badge from '#material-ui/core/Badge';
import IconButton from '#material-ui/core/IconButton';
import Tooltip from '#material-ui/core/Tooltip';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import { withStyles } from '#material-ui/core/styles';
import InputBase from '#material-ui/core/InputBase';
import { fade } from '#material-ui/core/styles/colorManipulator';
import MenuIcon from '#material-ui/icons/Menu';
import MailIcon from '#material-ui/icons/Mail';
import HomeIcon from '#material-ui/icons/Home';
import QuestionIcon from '#material-ui/icons/QuestionAnswer';
import CartIcon from '#material-ui/icons/ShoppingCart';
import PersonIcon from '#material-ui/icons/Person';
import SearchIcon from '#material-ui/icons/Search';
const styles = theme => ({
root: {
width: '100%',
},
grow: {
flexGrow: 1,
},
appBar: {
zIndex: 1300,
},
//search props for search bar
search: {
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginRight: theme.spacing.unit * 2,
marginLeft: 0,
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing.unit * 3,
width: 'auto',
},
},
searchIcon: {
width: theme.spacing.unit * 9,
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
inputRoot: {
color: 'inherit',
width: '100%',
backgroundColor: '#EAE9E8'
},
inputInput: {
paddingTop: theme.spacing.unit,
paddingRight: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
paddingLeft: theme.spacing.unit * 10,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('md')]: {
width: 200,
},
},
})
class Header extends Component {
onToggleNav = () => {
this.props.onToggleNav()
}
render() {
const { classes } = this.props;
return (
<header className={classes.root}>
<AppBar color="inherit" className={classes.appBar}>
<Toolbar>
<IconButton color="inherit" className={"remove_outline"} onClick={this.onToggleNav}>
<MenuIcon />
</IconButton>
<Typography variant="h6" color="inherit" noWrap>
Watch Shop
</Typography>
{/* search bar */}
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
/>
</div>
<div className={classes.grow} />
<div>
<Tooltip title="Trang chủ">
<IconButton className="remove_outline">
<HomeIcon />
</IconButton>
</Tooltip>
<Tooltip title="Hỗ trợ">
<IconButton className="remove_outline">
<QuestionIcon />
</IconButton>
</Tooltip>
<Tooltip title="Phản hồi">
<IconButton className="remove_outline">
<MailIcon />
</IconButton>
</Tooltip>
<Tooltip title="Tài khoản">
<IconButton className="remove_outline">
<PersonIcon />
</IconButton>
</Tooltip>
<Tooltip title="Giỏ đồ">
<IconButton className="remove_outline">
<Badge badgeContent={4} color="secondary">
<CartIcon />
</Badge>
</IconButton>
</Tooltip>
</div>
</Toolbar>
</AppBar>
</header>
);
}
}
const mapDispatchToProps = (dispatch, props) => {
return {
onToggleNav: () => {
dispatch(actions.isShowNav())
}
}
}
export default connect(null, mapDispatchToProps)(withStyles(styles)(Header));
Style tab in the Developer Tools
Style tab in the Developer Tools
Search bar:
Search bar

How to use styling from another called component?

I'm currently using the material-ui react library and have copied the responsive drawer component example.
Is there a possible way to separate the sidebar and header into a separate component and call the sidebar function and my own main content in the main section using the classes.content styling set in the sidebar component
<main className={classes.content}>
<Typography noWrap>{'You think water moves fast? You should see ice.'}
</Typography>
</main>
e.g my home function wants to use the side
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Drawer from 'material-ui/Drawer';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import List from 'material-ui/List';
import Typography from 'material-ui/Typography';
import IconButton from 'material-ui/IconButton';
import Hidden from 'material-ui/Hidden';
import Divider from 'material-ui/Divider';
import MenuIcon from 'material-ui-icons/Menu';
import { mailFolderListItems, otherMailFolderListItems } from './tileData';
const drawerWidth = 240;
const styles = theme => ({
root: {
width: '100%',
height: 430,
marginTop: theme.spacing.unit * 3,
zIndex: 1,
overflow: 'hidden',
},
appFrame: {
position: 'relative',
display: 'flex',
width: '100%',
height: '100%',
},
appBar: {
position: 'absolute',
marginLeft: drawerWidth,
[theme.breakpoints.up('md')]: {
width: `calc(100% - ${drawerWidth}px)`,
},
},
navIconHide: {
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
drawerHeader: theme.mixins.toolbar,
drawerPaper: {
width: 250,
[theme.breakpoints.up('md')]: {
width: drawerWidth,
position: 'relative',
height: '100%',
},
},
content: {
backgroundColor: theme.palette.background.default,
width: '100%',
padding: theme.spacing.unit * 3,
height: 'calc(100% - 56px)',
marginTop: 56,
[theme.breakpoints.up('sm')]: {
height: 'calc(100% - 64px)',
marginTop: 64,
},
},
});
class ResponsiveDrawer extends React.Component {
state = {
mobileOpen: false,
};
handleDrawerToggle = () => {
this.setState({ mobileOpen: !this.state.mobileOpen });
};
render() {
const { classes, theme } = this.props;
const drawer = (
<div>
<div className={classes.drawerHeader} />
<Divider />
<List>{mailFolderListItems}</List>
<Divider />
<List>{otherMailFolderListItems}</List>
</div>
);
return (
<div className={classes.root}>
<div className={classes.appFrame}>
<AppBar className={classes.appBar}>
<Toolbar>
<IconButton
color="contrast"
aria-label="open drawer"
onClick={this.handleDrawerToggle}
className={classes.navIconHide}
>
<MenuIcon />
</IconButton>
<Typography type="title" color="inherit" noWrap>
Responsive drawer
</Typography>
</Toolbar>
</AppBar>
<Hidden mdUp>
<Drawer
type="temporary"
anchor={theme.direction === 'rtl' ? 'right' : 'left'}
open={this.state.mobileOpen}
classes={{
paper: classes.drawerPaper,
}}
onRequestClose={this.handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
{drawer}
</Drawer>
</Hidden>
<Hidden mdDown implementation="css">
<Drawer
type="permanent"
open
classes={{
paper: classes.drawerPaper,
}}
>
{drawer}
</Drawer>
</Hidden>
<main className={classes.content}>
<Typography noWrap>{'You think water moves fast? You should see ice.'}</Typography>
</main>
</div>
</div>
);
}
}
ResponsiveDrawer.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};
export default withStyles(styles, { withTheme: true })(ResponsiveDrawer);
You can move separate styling into separate components by just moving the styling into the new React component. I've done your case as an example.
The main component:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Typography from 'material-ui/Typography';
const styles = theme => ({
content: {
backgroundColor: theme.palette.background.default,
width: '100%',
padding: theme.spacing.unit * 3,
height: 'calc(100% - 56px)',
marginTop: 56,
[theme.breakpoints.up('sm')]: {
height: 'calc(100% - 64px)',
marginTop: 64,
},
},
});
const Main = (props) => {
const { classes } = props;
return (
<main className={classes.content}>
<Typography noWrap>You think water moves fast? You should see ice.</Typography>
</main>
);
};
Main.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles, { withTheme: true })(Main);
The rest, using the extracted main component:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Drawer from 'material-ui/Drawer';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import List from 'material-ui/List';
import Typography from 'material-ui/Typography';
import IconButton from 'material-ui/IconButton';
import Hidden from 'material-ui/Hidden';
import Divider from 'material-ui/Divider';
import MenuIcon from 'material-ui-icons/Menu';
import { mailFolderListItems, otherMailFolderListItems } from './tileData';
const drawerWidth = 240;
const styles = theme => ({
root: {
width: '100%',
height: 430,
marginTop: theme.spacing.unit * 3,
zIndex: 1,
overflow: 'hidden',
},
appFrame: {
position: 'relative',
display: 'flex',
width: '100%',
height: '100%',
},
appBar: {
position: 'absolute',
marginLeft: drawerWidth,
[theme.breakpoints.up('md')]: {
width: `calc(100% - ${drawerWidth}px)`,
},
},
navIconHide: {
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
drawerHeader: theme.mixins.toolbar,
drawerPaper: {
width: 250,
[theme.breakpoints.up('md')]: {
width: drawerWidth,
position: 'relative',
height: '100%',
},
},
});
class ResponsiveDrawer extends React.Component {
state = {
mobileOpen: false,
};
handleDrawerToggle = () => {
this.setState({ mobileOpen: !this.state.mobileOpen });
};
render() {
const { classes, theme } = this.props;
const drawer = (
<div>
<div className={classes.drawerHeader} />
<Divider />
<List>{mailFolderListItems}</List>
<Divider />
<List>{otherMailFolderListItems}</List>
</div>
);
return (
<div className={classes.root}>
<div className={classes.appFrame}>
<AppBar className={classes.appBar}>
<Toolbar>
<IconButton
color="contrast"
aria-label="open drawer"
onClick={this.handleDrawerToggle}
className={classes.navIconHide}
>
<MenuIcon />
</IconButton>
<Typography type="title" color="inherit" noWrap>
Responsive drawer
</Typography>
</Toolbar>
</AppBar>
<Hidden mdUp>
<Drawer
type="temporary"
anchor={theme.direction === 'rtl' ? 'right' : 'left'}
open={this.state.mobileOpen}
classes={{
paper: classes.drawerPaper,
}}
onRequestClose={this.handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
{drawer}
</Drawer>
</Hidden>
<Hidden mdDown implementation="css">
<Drawer
type="permanent"
open
classes={{
paper: classes.drawerPaper,
}}
>
{drawer}
</Drawer>
</Hidden>
<Main />
</div>
</div>
);
}
}
ResponsiveDrawer.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};
export default withStyles(styles, { withTheme: true })(ResponsiveDrawer);
So, you can just pull the styling out with the React component that you're extracting. The docs give some more details about material-ui's styling system.

Resources