i have tried to center it using flexbox justify-content, but it didn't work
Then I tried by replacing the Typography component with a div tag, still, it didn't work
import {AppBar,Zoom,Toolbar,Typography,CssBaseline,useScrollTrigger,Fab,makeStyles,IconButton,Container } from '#material-ui/core'
import PropTypes from 'prop-types';
import KeyboardArrowUpIcon from '#material-ui/icons/KeyboardArrowUp';
import styles from './menu.module.css'
import MenuIcon from '#material-ui/icons/Menu'
const useStyles = makeStyles(theme => ({
root: {
position: "fixed",
bottom: theme.spacing(2),
right: theme.spacing(2)
}
}));
function ScrollTop(props) {
const { children, window } = props;
const classes = useStyles();
// Note that you normally won't need to set the window ref as useScrollTrigger
// will default to window.
// This is only being set here because the demo is in an iframe.
const trigger = useScrollTrigger({
target: window ? window() : undefined,
disableHysteresis: true,
threshold: 100
});
const handleClick = event => {
const anchor = (event.target.ownerDocument || document).querySelector(
"#back-to-top-anchor"
);
if (anchor) {
anchor.scrollIntoView({ behavior: "smooth", block: "center" });
}
};
return (
<Zoom in={trigger}>
<div onClick={handleClick} role="presentation" className={classes.root}>
{children}
</div>
</Zoom>
);
}
// ScrollTop.propTypes = {
// children: PropTypes.element.isRequired,
// /**
// * Injected by the documentation to work in an iframe.
// * You won't need it on your project.
// */
// window: PropTypes.func
// };
export default function BackToTop(props) {
return (
<React.Fragment>
<CssBaseline />
<AppBar>
<Toolbar>
<IconButton>
<MenuIcon
className={styles.icon}
edge="end"
color="inherit"
aria-label="menu"
/>
</IconButton>
<Typography align='center' variant="h5">
Información
</Typography>
</Toolbar>
</AppBar>
<Toolbar id="back-to-top-anchor" />
<Container>
<Typography></Typography>
</Container>
<ScrollTop {...props}>
<Fab color="secondary" size="small" aria-label="scroll back to top">
<KeyboardArrowUpIcon />
</Fab>
</ScrollTop>
</React.Fragment>
);
}}```
The problem is probably Toolbar does not center its children. You could do something like
const useStyles = makeStyles(theme => ({
root: {
position: "fixed",
bottom: theme.spacing(2),
right: theme.spacing(2)
},
toolBar: {
display: "flex",
justifyContent: "center",
alignItems: "center",
}
}));
and use it
<Toolbar className={classes.toolBar}>
<IconButton>
<MenuIcon
className={styles.icon}
edge="end"
color="inherit"
aria-label="menu"
/>
</IconButton>
<Typography align='center' variant="h5">
Información
</Typography>
</Toolbar>
To make sure the typography is centered all the time, you can wrap it with the component. Because Container always centers it's children, the typography will be centered as a result of that. Like this
<Container>
<Typography variant="h5">Información</Typography>
</Container>
Related
Trying to use tabs as links but I can't find any where that explains how to do it when you are styling a tab component. I get the syntax that if you use a Tab component you should do this:
<Tab value="..." component={Link} to="/" >
However if I have styled the Tab before and created an additional component like below, I can't find anything. I did this because I couldn't style the tab directly and I found this solution.
//Styled Tab
const StyledButton = styled(Button)(() => ({
...theme.typography.estimateBtn,
borderRadius: "50px",
marginLeft: "25px",
marginRight: "25px",
height: "50px",
}));
// nav container
const ToolBarCom: React.FC = () => {
const [value, setValue] = React.useState(0);
// handles classes for non react elements
const classes = useStyles();
const onChangeHandler = (e: React.SyntheticEvent, value: number) => {
setValue(value);
};
return (
<ToolBar disableGutters>
{/* <Typography variant='h3'>Arc Development</Typography> */}
<img src={logo} alt='company logo' className={classes.logo} />
<Tabs
value={value}
onChange={onChangeHandler}
textColor='secondary'
indicatorColor='primary'
className={classes.tabsContainer}
variant='scrollable'
scrollButtons='auto'>
<StyledTab value={0} label='Home' />
<StyledTab value={1} label='Services' />
<StyledTab value={2} label=' The Revolution' />
<StyledTab value={3} label='About Us' />
<StyledTab value={4} label=' Contact Us' />
</Tabs>
<StyledButton variant='contained' color='secondary'>
Free Trial
</StyledButton>
</ToolBar>
);
I had to restyle the Tab with useStyle hook. You have to find the root of the tab component. I couldn't find any documentation for the issue above. See below:
const useStyles = makeStyles(() => ({
logo: {
height: "5em",
},
tabsContainer: {
marginLeft: "auto",
color: "white",
},
tab: {
"&.MuiTab-root": {
...theme.typography.tab,
minWidth: 10,
marginLeft: "25px",
},
},
}));
I have mui v5 dialog that I am not able to set its width using style() component.
import {
Dialog,
DialogContent,
DialogTitle,
Paper,
Typography,
} from "#mui/material";
import { Close } from "#mui/icons-material";
import { styled } from "#mui/material/styles";
import ActionButton from "./ActionButton";
import React from "react";
const StyledDialog = styled(Dialog)(({ theme }) => ({
fullWidth: true, // it's not taking effect
maxWidth: "lg", // it's not taking effect
padding: theme.spacing(2),
position: "absolute",
top: theme.spacing(5),
"& MuiDialog-paper": {
padding: theme.spacing(2),
position: "absolute",
top: theme.spacing(5),
},
"& .MuiTypography-h6": {
paddingRight: "0px",
},
}));
export default function Popup(props) {
const { title, children, openPopup, setOpenPopup } = props;
return (
<StyledDialog open={openPopup} onClose={() => setOpenPopup(false)}>
<DialogTitle>
<div style={{ display: "flex" }}>
<Typography variant="h6" component="div" style={{ flexGrow: 1 }}>
{title}
</Typography>
<ActionButton
color="secondary"
onClick={() => setOpenPopup(false)}
>
<Close />
</ActionButton>
</div>
</DialogTitle>
<DialogContent dividers>{children}</DialogContent>
</StyledDialog>
However, if I listed the props directly inside the it works.
<StyledDialog fullWidth="true" maxWidth="lg">
</StyledDialog>
What is the correct way of setting up the width and maxWidth.
Try this on the styledDialog declaration:
const StyledDialog = styled((props) => (
<Dialog
fullWidth={true}
maxWidth={'lg'}
{...props}
/>
))(({ theme }) => ({
// Your code to style the dialog goes here
}));
The problem on your code is that you arent passing the properties fullWidth and maxWidth to the component.
You are trying to use maxWidth: lg and fullWidth: true like css, but they are only for the Dialog API.
So you could use maxWidth in the component as an API like
<Dialog maxWidth="lg" fullWidth ... >
or you can add it as css style using theme.
const StyledDialog = styled(Dialog)(({ theme }) => ({
maxWidth: theme.breakpoints.values.lg, // there's no styling such fullWidth
...
}));
You could have a look at the default theme.
i have inertia progress bar initialized in my app.js
app.js
import React from "react";
import { render } from "react-dom";
import { createInertiaApp } from "#inertiajs/inertia-react";
import { InertiaProgress } from "#inertiajs/progress";
createInertiaApp({
resolve: (name) => require(`./Pages/${name}`),
setup({ el, App, props }) {
render(<App {...props} />, el);
},
});
InertiaProgress.init({
// The color of the progress bar.
color: "red",
// Whether the NProgress spinner will be shown.
showSpinner: true,
});
but the progressbar won't appear every time I render the appbar in the layout, its only the layout file, because if I render without it The progressbar will appear as usual
here is my Layout.tsx
import {
Button,
Container,
ListItem,
ListItemIcon,
ListItemText,
useTheme,
} from "#mui/material";
import React from "react";
import { styled, 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 MenuIcon from "#mui/icons-material/Menu";
import ChevronLeftIcon from "#mui/icons-material/ChevronLeft";
import { listItems } from "./ListItems";
import { usePage } from "#inertiajs/inertia-react";
import { Inertia } from "#inertiajs/inertia";
import route from "ziggy-js";
import FlashMessage from "./FlashMessage";
import { withStyles } from "#mui/styles";
const Layout = ({
children,
title,
}: {
children: React.ReactNode;
title: React.ReactNode;
}) => {
const theme = useTheme();
const authUser: any = usePage().props.user;
const drawerWidth: number = 240;
interface AppBarProps extends MuiAppBarProps {
open?: boolean;
}
const [open, setOpen] = React.useState(false);
const toggleDrawer = () => {
setOpen(!open);
};
const handleLogout = () => {
if (confirm("are you sure want to logout?")) {
Inertia.post(route("logout"));
}
};
return (
<ThemeProvider theme={theme}>
<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, marginLeft: 2 }}
>
{title}
</Typography>
<Button
{...(authUser ? { display: "none" } : { sx: {} })}
variant="text"
color="inherit"
onClick={handleLogout}
>
Logout
</Button>
</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>{listItems}</List>
</Drawer>
<Box
component="main"
}}
>
<Toolbar />
<FlashMessage />
<Container sx={{ marginTop: "50px" }}>{children}</Container>
</Box>
</Box>
</ThemeProvider>
);
};
export default Layout;
I think my progressbar appears under the appbar, is there any solution to this problem?
Just find out what the zIndex for your AppBar is (1100 by default I think)
console.log(Theme.zIndex.appBar)
Then on your CSS file, add a line to make the zIndex of the progress bar higher:
#nprogress .bar {
z-index: 1101!important;
}
I am having an issue trying to use MUI Styled () on bigger scale: can someone take a look at the code we used to use in prior versions and let me know how to replicate it in MUI V5.
Old way:
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#fdfdff",
},
pageHeader: {
padding: theme.spacing(4),
display: "flex",
marginBottom: theme.spacing,
},
pageIcon: {
display: "inline-block",
padding: theme.spacing(2),
color: "#3c44b1",
},
pageTitle: {
paddingLeft: theme.spacing(4),
"& .MuiTypography-subtitle2": {
opacity: "0.6",
},
},
}));
export default function PageHeader(props) {
const classes = useStyles();
const { title, subTitle, icon } = props;
return (
<Paper elevation={0} square className={classes.root}>
<div className={classes.pageHeader}>
<Card className={classes.pageIcon}>{icon}</Card>
<div className={classes.pageTitle}>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</div>
</div>
</Paper>
);
}
My attempt to accomplish the same in MUI V5 is not working properly. it renders but it doesn't look the same and it's all over the place.
const rootStyle = styled("div")({
backgroundColor: "#fdfdff",
});
const headerStyle = styled("div")(({ theme }) => ({
padding: theme.spacing(4),
display: "flex",
marginBottom: theme.spacing,
}));
const iconStyle = styled("div")(({ theme }) => ({
display: "inline-block",
padding: theme.spacing(2),
color: "#3c44b1",
}));
const titleStyle = styled("div")(({ theme }) => ({
paddingLeft: theme.spacing(4),
"& .MuiTypography-subtitle2": {
opacity: "0.6",
},
}));
export default function PageHeader(props) {
const { title, subTitle, icon } = props;
return (
<rootStyle>
<Paper elevation={0} square>
<headerStyle>
<iconStyle>
<Card>{icon}</Card>
</iconStyle>
<titleStyle>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</titleStyle>
</headerStyle>
</Paper>
</rootStyle>
);
}
I am new to MUI and there are not a lot of examples out there that cover this. I truly appreciate your help!
Below is a v5 version of your code with the same look as the v4 version. I added default values for the props just for demonstration purposes.
You had two main issues:
You added additional div layers for the styling rather than styling the elements that originally received the styles (e.g. Paper, Card).
You assigned the styled divs to variable names that start with a lowercase letter which caused them to be rendered as DOM tags rather than components (so the styling would have been completely ignored).
From https://reactjs.org/docs/components-and-props.html#rendering-a-component:
React treats components starting with lowercase letters as DOM tags.
import Paper from "#mui/material/Paper";
import Card from "#mui/material/Card";
import Typography from "#mui/material/Typography";
import { styled } from "#mui/material/styles";
import PersonIcon from "#mui/icons-material/Person";
const StyledPaper = styled(Paper)({
backgroundColor: "#fdfdff"
});
const HeaderDiv = styled("div")(({ theme }) => ({
padding: theme.spacing(4),
display: "flex",
marginBottom: theme.spacing
}));
const StyledCard = styled(Card)(({ theme }) => ({
display: "inline-block",
padding: theme.spacing(2),
color: "#3c44b1"
}));
const TitleDiv = styled("div")(({ theme }) => ({
paddingLeft: theme.spacing(4),
"& .MuiTypography-subtitle2": {
opacity: "0.6"
}
}));
export default function PageHeader(props) {
const {
title = "Title",
subTitle = "sub-title",
icon = <PersonIcon />
} = props;
return (
<StyledPaper elevation={0} square>
<HeaderDiv>
<StyledCard>{icon}</StyledCard>
<TitleDiv>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</TitleDiv>
</HeaderDiv>
</StyledPaper>
);
}
An alternative (and much more concise) way to convert the v4 code to v5 is to use the sx prop:
import Paper from "#mui/material/Paper";
import Card from "#mui/material/Card";
import Typography from "#mui/material/Typography";
import PersonIcon from "#mui/icons-material/Person";
import Box from "#mui/material/Box";
export default function PageHeader(props) {
const {
title = "Title",
subTitle = "sub-title",
icon = <PersonIcon />
} = props;
return (
<Paper elevation={0} square sx={{ bgcolor: "#fdfdff" }}>
<Box sx={{ p: 4, display: "flex", mb: 1 }}>
<Card sx={{ display: "inline-block", p: 2, color: "#3c44b1" }}>
{icon}
</Card>
<Box sx={{ pl: 4, "& .MuiTypography-subtitle2": { opacity: 0.6 } }}>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</Box>
</Box>
</Paper>
);
}
Here is one more option using a single styled call, though in my opinion this would be more brittle to maintain than the other options:
import Paper from "#mui/material/Paper";
import Card from "#mui/material/Card";
import Typography from "#mui/material/Typography";
import { styled } from "#mui/material/styles";
import PersonIcon from "#mui/icons-material/Person";
const StyledPaper = styled(Paper)(({ theme }) => ({
backgroundColor: "#fdfdff",
"& > div": {
padding: theme.spacing(4),
display: "flex",
marginBottom: theme.spacing(1),
"& .MuiCard-root": {
display: "inline-block",
padding: theme.spacing(2),
color: "#3c44b1"
},
"& > div": {
paddingLeft: theme.spacing(4),
"& .MuiTypography-subtitle2": {
opacity: "0.6"
}
}
}
}));
export default function PageHeader(props) {
const {
title = "Title",
subTitle = "sub-title",
icon = <PersonIcon />
} = props;
return (
<StyledPaper elevation={0} square>
<div>
<Card>{icon}</Card>
<div>
<Typography variant="h6" component="div">
{title}
</Typography>
<Typography variant="subtitle2" component="div">
{subTitle}
</Typography>
</div>
</div>
</StyledPaper>
);
}
I have a tab component in Material-UI and I want to implement a tooltip on it.
My problem is that when I click the tab component, the tooltip is not disappearing. It must disappear after I click on that tab.
Currently, it continues to be visible even after I click on the tab.
How do I rectify that?
<Tabs
className="navbar-routes"
value={value}
style={{ color: 'green'}}
indicatorColor="secondary"
onChange={handleChange}
>
{
tabsData.map(({id,title,description}) => {
return(
<ToolTip description={description}>
<Tab
style={{
minWidth: 10,
fontSize: '80%',
fontWeight: 'bold',
marginLeft: '-4px',
marginRight: 4
}}
key={id}
component={Link}
to={`/${title}`}
label={`${title}`}
/>
</ToolTip>
);
}
)}
</Tabs>
If you look at the document of Material-UI tooltip API
You would find a props named disableHoverListener
bool
default: false
Do not respond to hover events.
Set it as True would turn off the tooltip onMouseOver event trigger.
Update
Or you can simply make it totally under control.
By binding the onClick, onMouseOver, onMouseLeave, open to related component.
import React, { useState } from "react";
import "./styles.css";
import { Tooltip, Tab } from "#material-ui/core";
export default function App() {
const [flg, setFlg] = useState(false);
const [isHover, setIsHover] = useState(false);
return (
<div className="App">
<Tooltip
title={"message"}
aria-label="add"
placement="bottom"
open={!flg && isHover}
>
<Tab
label={`Click: ${!flg ? "enabled" : "disabled"}`}
onClick={() => setFlg(!flg)}
onMouseOver={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
/>
</Tooltip>
</div>
);
}
Try it online:
You can also implement a generic tooltip with a managed state when to open/close the tooltip.
import Tooltip, { TooltipProps } from "#mui/material/Tooltip";
import { useState } from "react";
/**
* MUI Tooltip wrapper with adaption to the move away once focuses left.
*/
export function ManagedTooltip(props: TooltipProps) {
const [open, setOpen] = useState<boolean>(false);
// Wrap Tooltip with div to capture mouse events
return <div style={{ display: 'flex' }}
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
onClick={() => setOpen(false)}
>
{/* Show the original MUI Tooltip with all props. */}
{/* Just override the open attribute to be fully managed, and disable internal listeners */}
<Tooltip {...props} open={open} disableHoverListener disableFocusListener />
</div>;
}
Once it's ready, you can use it anywhere exactly like the original MUI tooltip.
<Tabs
className="navbar-routes"
value={value}
style={{ color: 'green'}}
indicatorColor="secondary"
onChange={handleChange}
>
{
tabsData.map(({id,title,description}) => {
return(
<ManagedTooltip description={description}>
<Tab
style={{
minWidth: 10,
fontSize: '80%',
fontWeight: 'bold',
marginLeft: '-4px',
marginRight: 4
}}
key={id}
component={Link}
to={`/${title}`}
label={`${title}`}
/>
</ManagedTooltip>
);
}
)}
</Tabs>
The way I solved this was by rendering the tooltip conditionally. In your case I suppose you want the tooltip not to render for the tab of the current active route:
function ConditionalTooltip({renderTooltip, children, ...props}) {
return renderTooltip ? <Tooltip {...props}>{children}</Tooltip> : children;
}
function Tabs() {
const location = useLocation();
return (
<Tabs
className="navbar-routes"
value={value}
style={{ color: 'green'}}
indicatorColor="secondary"
onChange={handleChange}
>
{
tabsData.map(({id,title,description}) => {
return(
<ConditionalTooltip
renderTooltip={location.pathname.indexOf(title) === -1} /* only render tooltip on not active urls */
title={description}
>
<Tab
style={{
minWidth: 10,
fontSize: '80%',
fontWeight: 'bold',
marginLeft: '-4px',
marginRight: 4
}}
key={id}
component={Link}
to={`/${title}`}
label={`${title}`}
/>
</ConditionalTooltip>
);
}
)}
</Tabs>
)
}