import React from 'react';
import ReactDOM from 'react-dom';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import {Tabs, Tab} from 'material-ui/Tabs';
const styles = {
headline: {
fontSize: 24,
paddingTop: 16,
marginBottom: 12,
fontWeight: 400,
},
};
const LoginTabs = () => (
<Tabs>
<Tab label="Login" >
<div>
<h2 style = {styles.headline}>Login</h2>
<p>
This is an example tab.
</p>
<p>
You can put any sort of HTML or react component in here. It even keeps the component state!
</p>
</div>
</Tab>
<Tab label="Sign Up" >
<div>
<h2 style = {styles.headline}>Sign Up</h2>
<p>
This is another example tab.
</p>
</div>
</Tab>
</Tabs>
);
class LoginApp extends React.Component {
constructor () {
super();
this.muiTheme = darkBaseTheme;
}
componentWillMount () {
console.log(this.muiTheme);
}
render() {
return(
<div>
{LoginTabs()}
</div>
)
}
}
const Main = () => (
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
<LoginApp />
</MuiThemeProvider>
);
// ========================================
ReactDOM.render(
<Main />,
document.getElementById('root')
);
The tabs are rendered with the default light theme even though I've specified that darktheme using muiThemeProvider.
Most of this code is copied from the material-ui website and I'm not sure what is wrong. Can anybody suggest a fix?
I think the palette is being overwritten at some point, but I'm not sure where.
You can place the MuiThemeProvider at the root - it is not required on all components.
You can make the theme dark by setting type to dark. While it's only a single property value change, internally it modifies the value of the following keys:
palette.text
palette.divider
palette.background
palette.action
The theme can be set up this way.
import CssBaseline from '#material-ui/core/CssBaseline';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
import { Provider } from 'react-redux';
const theme = createMuiTheme({
palette: {
type: 'dark',
},
});
export default function component(props) {
return (
<MuiThemeProvider theme={theme}>
<div>
<CssBaseline />
<Header />
<AppBody />
</div>
</MuiThemeProvider>
);
}
https://material-ui.com/customization/themes/#type-light-dark-theme-
Related
In the demo.js, I wanted to use the Card along with its CardHeader and put wordings inside the CardContent. Also, I will be using the CardComponent in other files as well. How can I make the CardComponent reusable?
Sample codes: https://codesandbox.io/s/basiccard-material-demo-forked-kkshx?file=/demo.js
Below are the codes for the demo.js:
import * as React from "react";
import CardComponent from "./CardComponent";
export default function BasicCard() {
return (
<>
<h1>Hello</h1>
<CardComponent />
</>
);
}
Below are the codes for the CardComponent:
import React from "react";
import Card from "#mui/material/Card";
import CardContent from "#mui/material/CardContent";
import { CardHeader } from "#mui/material";
const CardComponent = () => {
const CardStyle = {
maxWidth: 500,
margin: "0 auto",
marginBottom: "1rem",
marginTop: "1rem"
};
return (
<Card sx={{ minWidth: 275 }} elevation={5} style={CardStyle}>
<CardHeader title="Card Header Title here" />
<CardContent>//content here</CardContent>
</Card>
);
};
export default CardComponent;
I have another question as well under this component. Coming from material-ui4, mui5 was kind of confusing as I can no longer use the makeStyles. I tried adding this in the codesandbx example, however, it will say that dependency not found:
import { makeStyles } from '#mui/styles';
Hence, I settled with const CardStyle. Any help on how can I implement the newer version of the makeStyles? Also, do I need to install other dependecies from material-ui to make it work? Below is the package.json file.
Also in: https://www.reddit.com/r/reactjs/comments/sgqhh3/how_do_i_make_a_reusable_component_for_the_cards/
You can make it reusable adding props to your child card component. You can add as many props you want to make different cards using the same pattern.
To give styles to the component in mui v5 you have to use styled. You have to import it from #mui/material/styles
Here is the whole code of the new card component
import React from "react";
import {styled} from "#mui/material/styles"
import Card from "#mui/material/Card";
import CardContent from "#mui/material/CardContent";
import { CardHeader } from "#mui/material";
const StyledCard = styled((props) => (
<Card
{...props}
/>
))(({ theme }) => ({
maxWidth: 500,
margin: "0 auto",
marginBottom: "1rem",
marginTop: "1rem"
}));
const CardComponent = (props) => {
const {title,content}=props
return (
<StyledCard sx={{ minWidth: 275 }} elevation={5}>
<CardHeader title={title} />
<CardContent>{content}</CardContent>
</StyledCard>
);
};
export default CardComponent;
And here it is the whole codesandbox.
I am facing a problem with my custom theme, whenever i refreshes my
page my custom theme for Tabs and Button in Navbar disappears,
sometime it doesn't even loads the Tabs and estimate button custom
theme.
Also in Header.js file code it says theme is not used but i am using
it in makeStyle function. (theme is declared on line-2 of Header.js).
Following are my code File:
Header.js
import React, {useState} from 'react'
import theme from "./Theme";
import { makeStyles } from '#mui/styles';
import {AppBar, Box, Button, Tab, Tabs, Typography, useScrollTrigger} from "#mui/material";
import {Toolbar} from "#mui/material";
import logo from '../../assets/logo.svg'
function ElevationScroll(props) {
const { children} = props;
const trigger = useScrollTrigger({
disableHysteresis: true,
threshold: 0
});
return React.cloneElement(children, {
elevation: trigger ? 4 : 0,
});
}
const useStyles = makeStyles(theme=> ({
toolbarMargin: {
...theme.mixins.toolbar,
marginBottom:"3em"
},
companylogo:{
height:"7em"
},
tabName:{
marginLeft:"auto",
},
tab:{
...theme.typography.tab,
minWidth:10,
marginLeft:"25px",
color:"white"
},
estimateButton:{
...theme.typography.estimateButton,
height:"45px",
borderRadius:"25px",
marginLeft:"25px",
marginRight:"25px"
},
}))
function Navbar(){
const classes = useStyles();
const[value,setValue]=useState(0);
const handleChange=(e,value)=>
{
setValue(value);
}
return(
<React.Fragment>
<ElevationScroll>
<AppBar position={"fixed"}>
<Toolbar disableGutters={true}>
<img alt="company logo" className={classes.companylogo} src={logo} />
<Tabs className={classes.tabName} value={value} onChange={handleChange}>
<Tab className={classes.tab} label={"Home"}/>
<Tab className={classes.tab} label={"Services"}/>
<Tab className={classes.tab} label={"The Revolution"}/>
<Tab className={classes.tab} label={"About Us"}/>
<Tab className={classes.tab} label={"Contact Us"}/>
</Tabs>
<Button variant={"contained"} color={"secondary"} className={classes.estimateButton}>Free Estimate</Button>
</Toolbar>
</AppBar>
</ElevationScroll>
<div className={classes.toolbarMargin}/>
</React.Fragment>
);
}
export default Navbar;
Theme.js File:
import {createTheme} from "#mui/material/styles";
const arcBlue="#0B75B9";
const arcOrange="#FFA500";
const Theme = createTheme({
palette: {
primary: {
main: `${arcBlue}`
},
secondary: {
main: `${arcOrange}`
}
},
typography: {
tab:{
fontFamily:"Raleway",
fontWeight:1000,
fontSize:"1rem",
textTransform:"none",
color:"white"
},
estimateButton:{
fontFamily:"Raleway",
textTransform:"none",
fontWeight:700,
fontSize:"1rem",
height:"45px",
color:"white"
},
}
});
export default Theme;
App.js File:
import React from "react";
import Navbar from "../components/ui/header";
import {ThemeProvider} from "#mui/material/styles";
import theme from "./ui/Theme";
function App() {
return (
<>
<ThemeProvider theme={theme}>
<Navbar/>
</ThemeProvider>
</>
);
}
export default App;
I have created a theme in the index of my React.JS project using MUI. When I try to apply my style to my Appbar the theme does not correctly modify the menu button nor the menu itself. the button looks generic default and the menu remains white when it should match the color of the Appbar itself.
My index.tsx looks as such:
import React from "react";
import ReactDOM from "react-dom";
import AppbarTop from "./AppbarTop";
import { Router } from "react-router";
import { createBrowserHistory } from "history";
import AdapterDateFns from "#mui/lab/AdapterDateFns";
import { LocalizationProvider } from "#mui/lab";
import { createTheme } from "#mui/material";
import { ThemeProvider } from "#mui/styles";
import { StyledEngineProvider } from "#mui/material/styles";
const customHistory = createBrowserHistory();
const theme = createTheme({
palette: {
primary: {
main: "#242526"
},
secondary: {
main: "#d975d0"
},
text: {
primary: "#E4E6EB",
secondary: "#B0B3B8"
},
background: {
default: "#242526",
paper: "#242526"
}
}
});
ReactDOM.render(
<React.StrictMode>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Router history={customHistory}>
<ThemeProvider theme={theme}>
<StyledEngineProvider injectFirst>
<AppbarTop />
</StyledEngineProvider>
</ThemeProvider>
</Router>
</LocalizationProvider>
</React.StrictMode>,
document.getElementById("root")
);
My appbar.tsx looks like this:
import React from "react";
import {
AppBar,
Box,
Button,
Container,
Menu,
MenuItem,
Toolbar
} from "#mui/material";
import HomeIcon from "#mui/icons-material/Home";
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles((theme?: any) => ({
appBar: {
background: theme.palette.primary.main,
height: "60px",
position: "relative"
}
}));
const AppbarTop: React.FC<{ [key: string]: any }> = () => {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState<any>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<AppBar position="static" className={classes.appBar}>
<Toolbar>
<Button
id="basic-button"
aria-controls="basic-menu"
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
onClick={handleClick}
>
Dashboard
</Button>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button"
}}
>
<MenuItem onClick={handleClose}>
<HomeIcon />{" "}
</MenuItem>
</Menu>
{/*test speed dial*/}
<Container maxWidth="sm"></Container>
<Box></Box>
</Toolbar>
</AppBar>
</>
);
};
export default AppbarTop;
Can someone please explain what I am missing?
Change this line:
import { ThemeProvider } from "#mui/styles";
To:
import { ThemeProvider } from "#mui/material/styles";
Reason: There are 2 ThemeProviders here
The one from #mui/styles: This ThemeProvider does send the Theme object down via context, it works fine, you can still access it using the useTheme hook:
const theme = useTheme();
return <Box sx={{ width: 10, height: 10, bgcolor: theme.palette.primary.main }} />
The one from #mui/material/styles: This ThemeProvider is a wrapper of the above, but it also injects the theme to the StyledEngineThemeContext.Provider, which allows you to access the theme when using MUI API (sx prop/styled()). The problem here is that the Button and Menu components uses the styled() API under-the-hood so the ThemeProvider needs to be imported from #mui/material/styles to make it work.
return <Box sx={{ width: 10, height: 10, bgcolor: 'primary.main' }} />
Related answers
Difference between #mui/material/styles and #mui/styles?
Cannot use palette colors from MUI theme
MUI - makeStyles - Cannot read properties of undefined
Material UI Dark Mode
I am using React with react-pdf and trying to render a PDF into my modal. However, my modal gets loaded on a button click, so it's not loaded on app load. But it is trying to call the PDF rendering call on app load and thus generating the error: 'Error: Target container is not a DOM element'. I'm not sure of how to fix this issue.
Here is my entire modal component:
import ReactModal from 'react-modal';
import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import ReactPDF, { PDFViewer } from '#react-pdf/renderer';
import CloseButton from './CloseButton';
import MessageHub from '../message/MessageHub';
import PDFPlacard from '../placards/PDFPlacard';
const PDF = () => (
<PDFViewer>
<PDFPlacard />
</PDFViewer>
);
const PlacardsModal = (props) => {
const { openPlacards, setOpenPlacards, customStyles } = props;
const numPlacards = React.createRef();
const ref = useRef(null);
// this call needs to happen after the modal and #PDFPlacard is rendered
ReactDOM.render(<PDF />, document.getElementById('PDFPlacard'));
const handleSubmit = (evt) => {
evt.preventDefault();
if (numPlacards.current.value === '') {
ref.current('Please fill in the number of placards.');
} else {
// submit form
}
};
return (
<ReactModal
isOpen={openPlacards}
style={customStyles}
className={'print-placards-modal'}
closeTimeoutMS={1000}
>
<CloseButton setOpenModal={setOpenPlacards} />
<h2>Print Placards</h2>
{/* eslint-disable-next-line react/no-children-prop */}
<MessageHub children={(add) => (ref.current = add)} />
<form className={'form'} onSubmit={handleSubmit}>
<div className={'form-group row'}>
<label
htmlFor={'numPlacards'}
className={'col-sm-6 col-form-label'}
>
Number of Placards:
</label>
<div className={'col-sm-6'}>
<input
id={'numPlacards'}
type={'number'}
className={'form-control'}
ref={numPlacards}
/>
</div>
</div>
<button
className={'btn btn-primary d-block mx-auto mb-2'}
type={'submit'}
value={'Print'}
/>
</form>
<div id={'PDFPlacard'} />
</ReactModal>
);
};
PlacardsModal.propTypes = {
openPlacards: PropTypes.bool,
setOpenPlacards: PropTypes.func,
customStyles: PropTypes.object,
title: PropTypes.string
};
export default PlacardsModal;
Here is PDFPlacard.js:
import React from 'react';
import {
Page,
Text,
View,
Document,
StyleSheet
} from '#react-pdf/renderer';
// Create styles
const styles = StyleSheet.create({
page: {
flexDirection: 'row',
backgroundColor: '#E4E4E4'
},
section: {
margin: 10,
padding: 10,
flexGrow: 1
}
});
// Create Document Component
const PDFPlacard = (type) => (
<Document>
<Page size="letter" style={styles.page}>
<View style={styles.section}>
<Text>Section #1</Text>
</View>
<View style={styles.section}>
<Text>Section #2</Text>
</View>
</Page>
</Document>
);
export default PDFPlacard;
And my index.js:
import React from 'react';
import { render } from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min';
import './index.css';
import App from './App';
const title = 'title';
render(<App title={title} />, document.getElementById('root'));
// eslint-disable-next-line no-undef
module.hot.accept();
The parent is loading the PlacardsModal like this:
...
<button
className={'btn btn-info mb-3'}
onClick={() => setOpenPlacards(true)}
>
Placards
</button>
...
<PlacardsModal
openPlacards={openPlacards}
setOpenPlacards={setOpenPlacards}
customStyles={customStyles}
/>
Finally got the answer from another source. I should not have been making that ReactDOM.render( call at all. I should just have been including the PDF components on my page.
Like this:
...
<button
className={'btn btn-primary d-block mx-auto mb-2'}
type={'submit'}
value={'Print'}
/>
</form>
<!-- not this -->
<div id={'PDFPlacard'} />
<!-- this -->
<PDF />
</ReactModal>
);
};
...
I got stuck with showing loading icon on initial page loading. The code looks fine for me but some how it doesn't shows the loading icon. I am using material ui RefreshIndicator for loading icon. I am using material-ui V^0.18.7.
Here is my initial App.js code
import React, { Component } from 'react';
import HeaderTemplate from './Layout/Components/Header';
import FooterTemplate from './Layout/Components/Footer';
import RefreshIndicator from 'material-ui/RefreshIndicator';
import RaisedButton from 'material-ui/RaisedButton';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
class App extends Component {
constructor(props){
super(props);
this.state = {
showLoading: true
}
}
componentDidMount(){
this.setState({
showLoading: false
})
}
renderLoading(){
<RefreshIndicator
size={40}
left={10}
top={0}
status="loading"
style={{display: 'inline-block', position: 'relative'}}
/>
}
render() {
const muiTheme = imports.getMuiTheme({
});
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div>
<HeaderTemplate logo="Postme" />
<div id="demo-settings" className="">
</div>
<div className="container-fluid bodyfluid">
{this.state.showLoading ? this.renderLoading(): ''}
{this.props.children}
</div>
<FooterTemplate />
</div>
</MuiThemeProvider>
);
}
}
export default App;
Your method renderLoading() doesn't return anything. It just creates the JSX-Element into "nothing".
import React, { Component } from 'react';
import HeaderTemplate from './Layout/Components/Header';
import FooterTemplate from './Layout/Components/Footer';
import RefreshIndicator from 'material-ui/RefreshIndicator';
import RaisedButton from 'material-ui/RaisedButton';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
class App extends Component {
constructor(props){
super(props);
this.state = {
showLoading: true
}
}
componentDidMount(){
this.setState({
showLoading: false
})
}
renderLoading(){
return (<div style={{position: 'relative'}}>
<RefreshIndicator
size={40}
left={10}
top={0}
status="loading"
style={{display: 'inline-block', position: 'relative'}}
/>
</div>);
}
render() {
const muiTheme = imports.getMuiTheme({
});
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div>
<HeaderTemplate logo="Postme" />
<div id="demo-settings" className="">
</div>
<div className="container-fluid bodyfluid">
{this.state.showLoading ? this.renderLoading(): ''}
{this.props.children}
</div>
<FooterTemplate />
</div>
</MuiThemeProvider>
);
}
}
export default App;
Now it returns the JSX element your created, and it should be rendered as you like.