Utilize the global theme feature within React Material-UI to create a cohesive

I'm feeling a bit lost when it comes to setting up React Material-UI theme.

Even though I've tried to keep it simple, it's not working out for me as expected.

Here is the code snippet I have:

start.tsx

const theme = createMuiTheme({
    palette: {
        type: 'dark',
        primary: blue,
        secondary: lightGreen
    }
})

ReactDOM.render(
    <ThemeProvider theme={theme}>
        <BrowserRouter>
            <App />
        </BrowserRouter>
    </ThemeProvider>
    ,
    document.getElementById("root")
)

UserInterfaces.scan();

app.tsx

export class App extends React.Component<IProps, IState> {

    constructor(props) {
        super(props);
        this.state = {
            menu: null
        }
    }

    render() {
        if (!this.state.menu) {
            this.login();
            return <div>Loading ... </div>
        } else {
            return <div className="hx-top-frame">
                <div>
                    <MenuBar menuList={this.state.menu} />
                </div>
                <div>
                    Content here
                {/* <Content /> */}
                </div>
            </div>
        }
    }
}

menubar.tsx

export class MenuBar extends React.Component<IMenuProps, IMenuStates> {

    constructor(props) {
        super(props);
        this.state = { expanded: "" };
    }

    private setClose() {
        this.setState({ expanded: "" });
    }

    public render() {
        let menulist: IMenuArray[] = this.props.menuList.map<IMenuArray>(item => {
            return {
                path: item.path,
                icon: item.icon,
                link: Util.hyphenate(item.path)
            }
        })
        return <nav className="hx-menu">
            <Hidden smUp>
                <Drawer variant="temporary" anchor='left' open={this.state.expanded != ""} onClose={this.setClose.bind(this)} className="left-drawer">
                    <SubMenu menu={menulist} />
                </Drawer>
            </Hidden>
            <Hidden xsDown>
                <Drawer variant="permanent" anchor='left' open={this.state.expanded != ""} onClose={this.setClose.bind(this)} className="left-drawer">
                    <SubMenu menu={menulist}></SubMenu>
                </Drawer>
            </Hidden>
        </nav >
    }
}

submenu.tsx

class SubMenu extends React.Component<ISubMenuProps, IMenuStates> {

    constructor(props) {
        super(props);
        this.state = { expanded: "" };
    }

    public render() {
        let submenu: IMenuItems = {};
        let menuitems: IMenuArray[] = [];
        this.props.menu.forEach(menu => {
            let items = menu.path.split("/");
            let parent = items.length > 1;
            let name = items.shift();
            let child = items.join("/");
            if (!parent) {
                menuitems.push({ path: name, icon: menu.icon, link: menu.link });
            } else {
                if (!submenu[name]) submenu[name] = [];
                submenu[name].push({ path: child, icon: menu.icon, link: menu.link });
            }
        })

        return <List>
            {Object.keys(submenu).map(name => {
                let menu = name.split("/").shift();
                return <ListItem button className="hx-submenu" key={"m-" + name}>
                    <span className="hx-nowrap" onClick={() => { this.setState({ expanded: this.state.expanded == name ? "" : name }) }}>
                        <ListItemText primary={name} key={"t-" + name} />{this.state.expanded == name ? <ExpandLess /> : <ExpandMore />}
                    </span>
                    <Collapse in={this.state.expanded == name} timeout="auto" unmountOnExit className="hx-submenu">
                        <SubMenu menu={submenu[name]} />
                    </Collapse>
                </ListItem>
            })}

            {menuitems.map(item => {
                return <ListItem button component={RouterLink} to={item.link} key={"i-" + item.path}>
                    <ListItemText primary={item.path} className="hx-menu" key={"l-" + item.path} />
                </ListItem>
            })}

        </List>
    }
}

And now, my queries are:

  1. Why is the right panel light grey? How can I change it to blue?
  2. I want the drawer to stay open when there is enough window width. However, how do I prevent it from overlapping with the content part? And make it fixed on the left?
  3. How can I ensure the menu expands vertically instead of horizontally?
  4. I don't want to style each component individually. Is it possible to use a global theme throughout the project without customizing components? Even after following the documentation, it doesn't work as expected since my projects are based on classes rather than functions.

Code sandbox link: https://codesandbox.io/embed/theme-test-gwutc

Thank you.

Answer №1

I will provide responses for questions 1 and 4 at this time, as I am not yet aware of the answers for questions 2 and 3.

  1. The panel appears as light gray because it is set to the default color of Paper (Drawer utilizes Paper in its design).
    Paper is not influenced by palette.primary.
    To globally change the paper background color, you can implement the following:

    const theme = createMuiTheme({
      palette: {
        type: "dark",
        primary: blue,
        secondary: lightGreen,
        background: {
          paper: "blue" // drawers (and papers) will be blue due to this setting.
        }
      }
    });
    
  2. You can easily apply a global theme to all material-ui components. You are already achieving this by wrapping your app with ThemeProvider; you just need to adjust your theme accordingly.
    For instance, if you wish to override the default background color of drawers, you can do so as follows (a better alternative to option 1 above, as it does not affect paper components):

    const theme = createMuiTheme({
      overrides: { // you specify that you are overriding default material-ui styles
       MuiDrawer: {
         paper: {
           backgroundColor: 'blue',
         }
       }
      }
    });
    

Answer №2

I successfully managed to find solutions for all the challenges. I followed @ido's instructions for problems Number 1 and 4.

For Problem Number 2, the solution involved adding display:flex and setting a fixed width for the paper, following @ido's advice.

And now, here is the resolution for Problem Number 3.

submenu.tsx

.
.
<li>
    <ListItem button className="hx-submenu" key={"m-" + name}>
        <ListItemText primary={name} key={"t-" + name} onClick={() => {
            this.setState({
                expanded: this.state.expanded == name ? "" : name
            });
        }}
        />
        {this.state.expanded == name ? <ExpandLess /> : <ExpandMore />}
    </ListItem>
    <Collapse
        in={this.state.expanded == name}
        timeout="auto"
        unmountOnExit
        className="hx-submenu"
    >
        <SubMenu menu={submenu[name]} />
    </Collapse>
</li>
.
.

The issue was due to placing <Collapse> within <ListItem>. Consequently, the unnecessary <span> was removed as it served no purpose.

The updated codepen now reflects the corrected version.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How do I remove a specific object from my localStorage array in Angular?

Currently, I am storing and retrieving form values from localStorage. When displaying the data, I want to be able to remove a specific object that is clicked on. The issue is that my current code removes all the data instead of just the selected object. Be ...

Unable to determine the data type of the JSON object during the

I'm having trouble reading an Object type of json... Here is the json I'm working with: body: { "111": { "name": "name1", "status": 10000 }, "222": { "name": "name2", "status": 20000 }, "333": ...

Directive for masking input values

I am in need of an input that adheres to the following format: [00-23]:[00-59] Due to the limitations of Angular 2.4, where the pattern directive is unavailable and external libraries like primeNG cannot be used, I have been attempting to create a direct ...

Connecting two divs with lines in Angular can be achieved by using SVG elements such as

* Tournament Brackets Tree Web Page In the process of developing a responsive tournament brackets tree web page. * Connection Challenge I am facing an issue where I need to connect each bracket, represented by individual divs, with decorative lines linki ...

I am looking to update my table once I have closed the modal in Angular

I am facing an issue with refreshing the table in my component using the following function: this._empresaService.getAllEnterprisePaginated(1);. This function is located in my service, specifically in the modal service of the enterprise component. CODE fo ...

Is there cause for worry regarding the efficiency issues of utilizing Object.setPrototypeOf for subclassing Error?

My curiosity is piqued by the Object.setPrototypeOf(this, new.target.prototype) function and the cautionary note from MDN: Warning: Modifying an object's [[Prototype]] is currently a slow operation in all browsers due to how modern JavaScript engines ...

To ensure each row in the data grid component is distinct, it is necessary for them to possess a unique identifier property. Another option is to utilize the getRowId

I'm just starting out with React. I keep encountering an Error Mui: The data grid component is asking for a unique ID property for all rows. You can also use the getRowId prop to define a custom id for each row. I've tried a few things but not ...

MUI - The helper text for a Select using a TextField is appearing below the input field rather than within the input field itself

This is how the content will be displayed. https://i.stack.imgur.com/fwvcW.png Displayed below is the code for rendering: <Grid container spacing={2}> <Grid item xs={space} key={1}> <TextField value={""} onChang ...

Migration of Angular dynamic forms project - The error "input" does not have an initializer or a constructor, and another issue with Type T | undefined

Angular dynamic forms project migration - encountering Type T | undefined error In my quest to find a sample project demonstrating the creation of Angular forms using JSON datasets, I stumbled upon this repository: https://github.com/dkreider/advanced-dyn ...

NextJS Typescript Layout is throwing errors due to the absence of required props

After following the instructions on https://nextjs.org/docs/basic-features/layouts#with-typescript and making changes to my Home page as well as _app.tsx, I encountered an issue with the layout file Layout.tsx. The provided guide did not include an exampl ...

Error when attempting to add data into MongoDB using Node.JS: "The type 'string' cannot be assigned to type 'ObjectId | undefined'."

Attempting to add a document to the collection results in an error when specifying the _id field of the added document. How can I insert a document with an _id that is not an ObjectId? The error occurs with the following code. Omitting the _id resolves th ...

The application was not functioning properly due to an issue with the getSelectors() function while utilizing @ngrx/entity to

Currently, I am facing an issue with implementing a NgRx store using @ngrx/entity library. Despite Redux Devtools showing my collection loaded by Effect() as entities properly, I am unable to retrieve any data using @ngrx/entity getSelectors. Thus, it seem ...

Troubleshooting the issue of Angular 2 error: Cannot access the 'getOptional' property

Currently, I am navigating my way through angular 2 and attempting to define a service named searchservice. I want to inject this service in the bootstap part of my project: import {SearchService} from 'src/service'; Here is the code for the Se ...

Is it possible to use jQuery to set a value for a form control within an Angular component?

I'm currently working on an Angular 5 UI project. In one of my component templates, I have a text area where I'm attempting to set a value from the component.ts file using jQuery. However, for some reason, it's not working. Any suggestions o ...

What is the primary purpose of the index.d.ts file in Typescript?

There are some projects that include all types declarations within the index.d.ts file. This eliminates the need for programmers to explicitly import types from other files. import { TheType } from './somefile.ts' Is this the proper way to use ...

What causes the discrepancy in calculating marginTop on a desktop browser compared to a mobile browser?

In the top screenshot, you can see a representation of my Pixel 6XL connected to my laptop in USB debug mode. The checkered area represents the URL bar on the Chrome browser displayed on my Pixel device. Below that, the second screenshot shows the view fr ...

Dealing with Numerous Checkboxes using Material UI and Formik

I'm working on a form that includes a checkbox group with 4 checkboxes. My goal is to pass these values to an API upon submitting the form using Formik. There are specific conditions based on which checkboxes are checked: If the 'Height' c ...

Obtain a segment of the string pathway

In this scenario, there is a file path provided below. Unlike the rest of the URL, the last part (referred to as video2.mp4) regularly changes. The language used for this project is either Javascript or Typescript. file:///data/user/0/com.sleep.app/files/ ...

Error message: Injector Error: R3InjectorError(Standalone[_AppComponent])[_WebService -> _WebService -> _WebService] occurred

Being a student, I must apologize in advance for any mistakes in terminology or gaps in my understanding. I am currently developing an Angular front-end to communicate with my backend API. However, I keep encountering the following error in the web page c ...

I am interested in creating a class that will produce functions as its instances

Looking to create a TypeScript class with instances that act as functions? More specifically, each function in the class should return an HTMLelement. Here's an example of what I'm aiming for: function generateDiv() { const div = document.crea ...