TextField Material UI in dark mode - reactjs

I have a basic implementation of dark mode with material UI and React, the question is how to make TextField helper text, label, border changing according to dark and light mode toggled.
TextField is:
<TextField helperText='Sample text' label="Title" variant="outlined" />
Updated:
It's necessary TextField to have dark colored helperText, label, border in light mode, and light coloured in dark mode.
There is basic implementation of dark, light mode:
import { createTheme, ThemeProvider } from '#material-ui/core/styles'
import Paper from '#material-ui/core/Paper'
import Switch from '#material-ui/core/Switch'
function App() {
const [dark, setDark] = useState(false)
const theme = createTheme({
palette: {
type: dark ? 'dark' : 'light',
},
})
return (
<Router>
<ThemeProvider theme={theme}>
<Paper>
<Header></Header>
<Switch checked={dark} onChange={() => setDark(!dark)} />
<main className='py-3'>
<Container>
<Routes>
<Route exact path="/" element={<HomeScreen />}></Route>
...
</Routes>
</Container>
</main>
<Footer></Footer>
</Paper>
</ThemeProvider>
</Router>
);
}
export default App;
Some of the elements correspond to light, dark mode toggling, TextField not.

You can do it like this, as answered here Theme dark turns textfield to white
I added the helper text:
import React from "react";
import TextField from "#material-ui/core/TextField";
import { createMuiTheme } from "#material-ui/core/styles";
import { ThemeProvider } from "#material-ui/styles";
import CssBaseline from "#material-ui/core/CssBaseline";
const theme = createMuiTheme({
palette: {
type: "dark"
}
});
export default function FilledTextFields() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<TextField
id="myfilled-name"
helperText='Sample text'
label="Name"
variant="filled"
/>
</ThemeProvider>
);
}

If what you ask for is to change the style of hintText and label, you should see the Customization section of Material-UI
On the other hand, if you want to change the hintText itself on theme mode change, you have to use a global state to keep track of your theme mode.
const App = () => {
const [isDark, setIsDark] = useState(false)
return (
<TextField helperText={!isDark ? 'Sample text' : 'Some other text'} label="Title" variant="outlined" />
)
}

Related

MUI - dark theme doesn't change anything

I am new to MUI, but all was pretty easy to understand beside changing to dark theme.
I opened documentation of MUI at page where there are examples with dark theme. I copied the first example and it didn't work to me. Why doesn't this simple code example change my MUI theme to 'dark' mode? from here I understood that I need to add more components, but I didn't really understand what does it mean. If I don't add DOM tree it doesn't work? Why the background doesn't change?!
import React from 'react';
import { ThemeProvider, createTheme } from '#mui/material/styles';
function App() {
const darkTheme = createTheme({
palette: {
mode: 'dark'
},
});
return (
<ThemeProvider theme={darkTheme}>
Hello World
</ThemeProvider>
);
}
export default App;
You shoul add <CssBaseline />
import React from 'react';
import { ThemeProvider, createTheme } from '#mui/material/styles';
function App() {
const darkTheme = createTheme({
palette: {
mode: 'dark'
},
});
return (
<ThemeProvider theme={darkTheme}>
<CssBaseline />
Hello World
</ThemeProvider>
);
}
export default App;

MUI createTheme fonts

Just as the title says. Not sure what's wrong exactly, and would love to learn what I'm doing that's making this not work. I tested the import to see if it works through the web console, and it does, so I'm doing something wrong with createTheme. Here's my code:
import React from 'react';
import AppBar from '../components/appbar';
import { Typography } from '#mui/material'
import Footer from '../components/footer';
import { ThemeProvider, createTheme } from "#mui/material/styles";
const theme = createTheme({
typography: {
fontFamily: [
'Press Start 2P',
'cursive',
].join(','),
},});
const Home = props => {
return (
<div>
<AppBar title="Home" />
<ThemeProvider theme={theme}>
<Typography variant="h2">
Hello World!
</Typography>
</ThemeProvider>
<Footer />
</div>
);
}
export default Home;
Any help is thoroughly appreciated. Thank you very much for your time.

Material UI override react subtree except for certain components

Is there a way to override the theme of a react sub-tree, but skip the override for certain components?
I'm overriding all children of a component, making sure all the font size is small, using:
const overrideTheme = (theme: Theme): Theme => {
return createTheme({
...theme,
typography: {
fontSize: 11,
}
})
}
const MyCustomThemeWrapper = ({children}) => {
return (
<div>
<ThemeProvider theme={overrideTheme}>
{children}
</ThemeProvider>
</div>
)
}
What I want to do is make this override exclude certain components (and their children). In particular, I don't want to override the font size of any Dialog components that's part of the children subtree. Any way I can do this, without having to "re-override" the theme for each Dialog? I.e. I want something this:
const Component1 = () => {
return (
<MyCustomThemeWrapper>
<div>
This text has fontSize 11
<span> more font size 11</span>
<Dialog open={open}>
<DialogContent>
This text has the "original" fontSize
</DialogContent>
</Dialog>
</div>
</MyCustomThemeWrapper>
)
}
where the custom theme override "hits" all the children of MyCustomThemeWrapper except for the Dialog subtree. I know I'm asking for much here, but would be really nice if this was possible.
You can override inline component's styles with wrapping another ThemeProvider as a parent to inline components. For instance, If you would like to except the Dialog component from override ThemeProvider, You should wrap it with another ThemeProvider. Because of your code wasn't clear enough to describing on it, I've made another example which in that inline checkboxs styles, override by another ThemeProvider:
import React from "react";
import { createTheme, ThemeProvider } from "#material-ui/core/styles";
import Checkbox from "#material-ui/core/Checkbox";
import { green, orange } from "#material-ui/core/colors";
const outerTheme = createTheme({
palette: {
secondary: {
main: orange[500]
}
}
});
const innerTheme = createTheme({
palette: {
secondary: {
main: green[500]
}
}
});
const CustomCheckBox = () => {
return (
<ThemeProvider theme={innerTheme}>
<Checkbox defaultChecked />
</ThemeProvider>
);
};
export default function App() {
return (
<ThemeProvider theme={outerTheme}>
<Checkbox defaultChecked />
<Checkbox defaultChecked />
<CustomCheckBox />
</ThemeProvider>
);
}
Here's the result:

Switch between dark and light theme in non-material ui component

I am trying to introduce a theme switcher in my app. I have a lot of non-material-ui elements that I need the theme to reflect the changes on them.
The code below shows that I have a state that is called darkState that is set to true. The material ui components in my app reflect those changes but for example the div below does not get the dark color of the dark theme. What is that I am doing wrong in here?
import React, { useState } from "react";
import Header from "./components/Header.js";
import TopBar from "./components/TopBar.js";
import Sequence from "./components/Sequence.js";
import SecondaryWindow from "./components/SecondaryWindow.js";
import { MuiThemeProvider, createMuiTheme, makeStyles } from "#material-ui/core/styles";
import "./App.css";
import { MainContextProvider } from "./contexts/mainContext.js";
function App() {
const [darkState, setDarkState] = useState(true);
const palletType = darkState ? "dark" : "light";
const theme = createMuiTheme({
palette: {
secondary: {
main: "#0069ff",
},
type: palletType,
},
});
const useStyles = makeStyles((theme) => ({
root: {
paddingLeft: 80,
height: "100%",
backgroundColor: theme.palette.background.default,
},
}));
const classes = useStyles();
return (
<MuiThemeProvider theme={theme}>
<MainContextProvider>
<div className={classes.root}>
<Header />
<TopBar />
<Sequence />
<SecondaryWindow />
</div>
</MainContextProvider>
</MuiThemeProvider>
);
}
export default App;
Now I know the answer, in my example, the class root is not able to benefit from the custom-created theme that is provided by MuiThemeProvider. Instead, it uses the original theme that comes in Mui. To solve this, I separated that div into a component. This way, the theme context (custom-theme from MuiThemeProvider) can be accessed by the div. This way when I switch DarkState, colors update on Mui components and HTML elements based on the custom theme palette.
import React, { useContext, useState } from "react";
import Header from "./components/Header.js";
import TopBar from "./components/TopBar.js";
import Sequence from "./components/Sequence.js";
import SecondaryWindow from "./components/SecondaryWindow.js";
import { MuiThemeProvider, createMuiTheme, makeStyles } from "#material-ui/core/styles";
import "./App.css";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { MainContextProvider } from "./contexts/mainContext.js";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
function AppContent() {
const useStyles = makeStyles((theme) => ({
root: {
paddingLeft: 80,
height: "100%",
backgroundColor: theme.palette.background.default,
},
}));
const classes = useStyles();
return (
<div className={classes.root}>
<Header />
<TopBar />
<Sequence />
<SecondaryWindow />
</div>
);
}
function App() {
const [darkState, setDarkState] = useState(true);
const palletType = darkState ? "dark" : "light";
const theme = createMuiTheme({
palette: {
secondary: {
main: "#0069ff",
},
type: palletType,
},
});
return (
<MuiThemeProvider theme={theme}>
<MainContextProvider>
<AppContent />
</MainContextProvider>
</MuiThemeProvider>
);
}
export default App;
It's because you only change the #material component not the CSS, to change the CSS Theme, you need to make variable for CSS for Dark Theme.
on :root declare all the light theme color and div.darkmode all the darkmode:
:root {
--color-bg: #fff;
--color-text: #000;
}
.div.darkmode {
--color-bg: #363636;
--color-text: #d1d1d1;
}
/** Usage */
.div {
color: var(--color-text);
background: var(--color-bg)
}
and make a condition on the div when the dark theme is true a new classname darkmode will be added to dive as you wrote above
<div className={`${classes.root} ${darkState && `darkmode`}`}>
<Header />
<TopBar />
<Sequence />
<SecondaryWindow />
</div>
I created an example for you here.
let us know if anything goes wrong!
workaround 2
if you're not doing any customer style by CSS file then this will work
import React from 'react';
import CssBaseline from '#material-ui/core/CssBaseline';
export default function MyApp() {
return (
<MuiThemeProvider theme={theme}>
<CssBaseline />
{/* The rest of your application */}
</MuiThemeProvider>
);
}
I would declare both variations of your theme as constants above the mounting or rendering. This way you are not literally creating a new theme ever time your theme swaps. I would have a state holding the reference to the MUI-Theme constant.
You can manipulate data-theme attribute to toggle the dark/light theme. Try it on StackBlitz.
Setting up themes
Use data-theme attribute to set the selected theme.
/* default theme (light) */
:root {
--primary-color: #302ae6;
--secondary-color: #536390;
--font-color: #424242;
--bg-color: #fff;
}
/* dark theme */
[data-theme='dark'] {
--primary-color: #9a97f3;
--secondary-color: #818cab;
--font-color: #e1e1ff;
--bg-color: #161625;
}
Switching theme in React Hooks
// App.js
const [theme, setTheme] = useState({
light: true,
});
const handleChangeTheme = (event) => {
setTheme({ ...theme, [event.target.name]: event.target.checked });
};
Set our data-theme attribute accordingly
const currentTheme = theme.light === true ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', currentTheme);

How to make react-admin default theme RTL

I need to make react-admin which uses material-ui underneath into RTL, so far nothing works because there are styles on each element overriding dir="rtl" on body tag, creating a custom theme like:
const theme = {
direction: 'rtl',
isRtl: true
};
const themeWithDirection = createMuiTheme({...defaultTheme, ...theme});
and using it on Admin component like:
<Admin locale="ar" dataProvider={dataProvider} i18nProvider={i18nProvider} theme={themeWithDirection} layout={layout}>
did not work. also usign StyleProvider on custom layout did not work:
import React from 'react';
import { Layout } from 'react-admin';
import { create } from 'jss';
import rtl from 'jss-rtl';
import { jssPreset } from '#material-ui/core/styles';
import { StylesProvider } from '#material-ui/core/styles';
const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
const MyLayout = props =>
<StylesProvider jss={jss}>
<Layout
{...props}
/>
</StylesProvider>;
The problem is that components like TextField use text-align: left;, so how can I flip their css without overriding them in a custom css file?
Using the ListGuesser I had no luck switching the grid to RTL, however, after writing a custom list component and JssProvider it now works:
import React from 'react';
import { List, Datagrid, TextField, EmailField } from 'react-admin';
import { create } from 'jss';
import rtl from 'jss-rtl';
import JssProvider from 'react-jss/lib/JssProvider';
import { jssPreset } from '#material-ui/core/styles';
const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
export const UserList = props => (
<JssProvider jss={jss}>
<List {...props}>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="name" />
<TextField source="username" />
<EmailField source="email" />
<TextField source="address.street" />
<TextField source="phone" />
<TextField source="website" />
<TextField source="company.name" />
</Datagrid>
</List>
</JssProvider>
);

Resources