I am using react-tooltip, react-emotion.
I cannot figure out how to style the span in order to override default styles.
Here's what I've got so far:
import React, { PureComponent } from 'react';
import styled from 'react-emotion';
const myTooltip = (Wrapper, toolTip) => {
class TooltipWrap extends PureComponent {
render() {
return (
<span
data-tip={toolTip}
data-delay-show="250"
data-place="bottom"
className={TooltipStyle}
>
<Wrapper
{...this.props}
/>
</span>
);
}
}
return TooltipWrap;
};
export default withToolTip;
const TooltipStyle = styled.span ({
color: 'red !important';
fontSize: '48px !important';
})
Anyone have any tips or a specific definitive guide on how to style this span so I can override the defaults in react-tooltip?
The documentation is pretty spotty, and there's literally no examples anywhere on the web.
I ran into a similar issue but was able to override the default styles using styled components and passing it the ReactTooltip component
import React, { PureComponent } from 'react';
import styled from 'react-emotion';
import ReactTooltip from 'react-tooltip';
const myTooltip = (Wrapper, toolTip) => {
class TooltipWrap extends PureComponent {
render() {
return (
<span
data-tip={toolTip}
data-delay-show="250"
data-place="bottom"
>
// Replace ReactTooltip component with styled one
<ReactTooltipStyled type="dark" />
<Wrapper
{...this.props}
/>
</span>
);
}
}
return TooltipWrap;
};
export default withToolTip;
export const ReactTooltipStyled = styled(ReactTooltip)`
&.place-bottom {
color: red;
font-size: 48px;
}
`;
Using this method all you would need to do is import the newly styled component into your React file and replace the original ReactTooltip with the ReactTooltipStyled component.
Related
I'm trying to override the existing styling for a button in MUI. This is my first time using MUI, and I installed my project with the default emotion as a styling engine. I tried to use the css() method as specified here : The css prop however it doesn't seem to be working, even on the example case provided.
I would have tried to add a custom css file to handle :select, but I'm using state in my component to change from selected to not selected.
import * as React from "react";
import Avatar from "#mui/material/Avatar";
import ListItemText from "#mui/material/ListItemText";
import ListItemButton from "#mui/material/ListItemButton";
import { useState } from "react";
import { css } from "#emotion/react";
const ProfileInfo = ({ userCredentials, userPicture }) => {
const [selected, setSelected] = useState(false);
return (
<ListItemButton
selected={selected}
onClick={() => setSelected((prev) => !prev)}
css={css`
::selection {
color: #2e8b57;
}
:focus {
color:#2e8b57;
}
:active {
color:#2e8b57
}
`}
>
<Avatar
alt={userCredentials}
src={userPicture}
sx={{ width: 24, height: 24 }}
/>
<ListItemText primary={userCredentials} sx={{ marginLeft: 3 }} />
</ListItemButton>
);
};
export default ProfileInfo;
Working examples on Code Sandbox
I have made a similar example using Code Sandbox, which you can find here https://codesandbox.io/s/amazing-gagarin-gvl66n. I show a working implementation using:
The css prop
The sx prop
Using the css prop
There's two things you need to do to make your code work using Emotion's css prop.
Add the following lines, which is also in the example, at the top of the file where you are using the css prop. This will tell your app how to handle the css prop.
/* eslint-disable react/react-in-jsx-scope -- Unaware of jsxImportSource */
/** #jsxImportSource #emotion/react */
Target the classes Material UI provides for the List Item Button component. For example, if I want to style the List Item Button when selected is true, I would target the .Mui-selected class.
I am assuming you wanted to style the background color of the List Item Button rather than the color. Styling the color changes the font color. However, if you wanted to change the font color, you can just change each instance of background-color to color.
Putting it altogether:
/* eslint-disable react/react-in-jsx-scope -- Unaware of jsxImportSource */
/** #jsxImportSource #emotion/react */
import * as React from "react";
import Avatar from "#mui/material/Avatar";
import ListItemText from "#mui/material/ListItemText";
import ListItemButton from "#mui/material/ListItemButton";
import { useState } from "react";
import { css } from "#emotion/react";
const ProfileInfo = ({ userCredentials, userPicture }) => {
const [selected, setSelected] = useState(false);
return (
<ListItemButton
selected={selected}
onClick={() => setSelected((prev) => !prev)}
css={css`
&.Mui-selected {
background-color: #2e8b57;
}
&.Mui-focusVisible {
background-color: #2e8b57;
}
:hover {
background-color: #2e8b57;
}
`}
>
<Avatar
alt={userCredentials}
src={userPicture}
sx={{ width: 24, height: 24 }}
/>
<ListItemText primary={userCredentials} sx={{ marginLeft: 3 }} />
</ListItemButton>
);
};
export default ProfileInfo;
Alternative: Using the SX prop
The sx prop can be used to override styles with all Material UI components. You are already using this for the Avatar and ListItemText components in your example.
Using the sx prop, the equivalent code would be:
import * as React from "react";
import Avatar from "#mui/material/Avatar";
import ListItemText from "#mui/material/ListItemText";
import ListItemButton from "#mui/material/ListItemButton";
import { useState } from "react";
const ProfileInfo = ({ userCredentials, userPicture }) => {
const [selected, setSelected] = useState(false);
return (
<ListItemButton
selected={selected}
onClick={() => setSelected((prev) => !prev)}
sx={{
"&.Mui-selected": {
backgroundColor: "#2e8b57"
},
"&.Mui-focusVisible": {
backgroundColor: "#2e8b57"
},
":hover": {
backgroundColor: "#2e8b57"
}
}}
>
<Avatar
alt={userCredentials}
src={userPicture}
sx={{ width: 24, height: 24 }}
/>
<ListItemText primary={userCredentials} sx={{ marginLeft: 3 }} />
</ListItemButton>
);
};
export default ProfileInfo;
It looks like MUI components doesn't use standard CSS rules but instead has a defined set of CSS rules you can modify https://mui.com/material-ui/api/list-item/#props.
I am using Next.js with Material-UI as the framework.
I have Layout component that wraps the contents with Material-UI <Container>.
I would like to override the style of Layout that limits the width of background, so that the background would extend to the full screen.
components/Layout.js
import { Container } from '#material-ui/core';
export default function Layout({ children }) {
return <Container>{children}</Container>;
}
pages/_app.js
import Layout from '../components/Layout';
...
<Layout>
<Component {...pageProps} />
</Layout>
...
pages/index.js
export default function App() {
return (
<div style={{ backgroundColor: "yellow" }}>
Home Page
</div>
)
}
Using Layout component comes in handy in most cases but sometimes I do want to override the certain styles of Layout from the child component.
In this case, how do I override the style of Layout component that puts the limit on maxWidth?
I tried to add {width: '100vw'} inside the style of pages/index.js, but did not work.
Any help would be appreciated.
Link to the SandBox
Using React Context is how I've solved this issue.
context/ContainerContext.js
import React from 'react';
const ContainerContext = React.createContext();
export default ContainerContext;
components/Layout.js
import React, { useState } from 'react';
import { Container } from '#material-ui/core';
import ContainerContext from '../context/ContainerContext';
export default function Layout({ children }) {
const [hasContainer, setHasContainer] = useState(true);
const Wrapper = hasContainer ? Container : React.Fragment;
return (
<ContainerContext.Provider value={{ hasContainer, setHasContainer }}>
<Wrapper>{children}</Wrapper>
</ContainerContext.Provider>
);
}
pages/index.js
import { useContext, useLayoutEffect } from 'react';
import ContainerContext from '../context/ContainerContext';
export default function App() {
const { setHasContainer } = useContext(ContainerContext);
// Where the magic happens!
useLayoutEffect(() => {
setHasContainer(false);
}, []);
return (
<div style={{ backgroundColor: "yellow" }}>
Home Page
</div>
);
}
I'm using react-bootstrap. I'm trying to style a custom checkbox since it seems it makes it possible. Tho, it doesn't work. I'm doing what the documentation tells me.
This is my code.
import * as React from "react";
import { t as typy } from 'typy';
import _ from 'lodash';
import { Form, FormCheck } from "react-bootstrap";
import { ErrorMessage } from "formik";
export type Props = {
isChecked: Boolean,
changeHandler: Function
}
export const Checkbox = ({
isChecked,
changeHandler
}: Props) => {
return (
<Form>
{['checkbox', 'radio'].map((type) => (
<div key={`custom-${type}`} className="mb-3">
<Form.Check
custom
type={type}
id={`custom-${type}`}
label={`Check this custom ${type}`}
/>
<Form.Check
custom
disabled
type={type}
label={`disabled ${type}`}
id={`disabled-custom-${type}`}
/>
</div>
))}
</Form>
);
};
export default Checkbox;
This is my css. I just want to see if it applies the style:
#custom-checkbox {
background-color: red;
width: 10rem;
}
You can use .custom-control-input and .custom-control-label classes to apply custom style to the custom checkbox in react-bootstrap.
I'd like to implement switching between dark/light theme dynamically with Ant design v4.
It's possible to customize the theme with other CSS/LESS imports as it's written here:
https://ant.design/docs/react/customize-theme#Use-dark-theme
But I'm not sure how to switch between those themes dynamically from the code. I have a variable in my React app (darkMode) which indicates if the dark theme is currently used. I have to provide correct CSS files when this variable is changed. But I can't import CSS dynamically only when some condition is fulfilled, because it's not way how the imports work.
I tried to do something messy with require like in the following code, but it's a very very bad approach and it's still not working properly (because CSS is injected but probably not withdrawn.
):
const Layout = () => {
...
useEffect(() => {
if (darkMode === true) {
require("./App.dark.css")
} else {
require("./App.css")
}
}, [darkMode])
return (
<Home />
)
}
It should be possible to switch themes somehow because it's already implemented in Ant design docs (https://ant.design/components/button/):
Do you have any idea how to do it?
Thanks!
This is what I am using for now -
PS -
I don't know if this will yield optimal bundle size.
changing theme results in a page reload.
make a folder called "themes" - it would have 6 files -> dark-theme.css, dark-theme.jsx, light-theme.css, light-theme.jsx, use-theme.js, theme-provider.jsx. Each of them is described below.
dark-theme.css
import "~antd/dist/antd.dark.css";
dark-theme.jsx
import "./dark-theme.css";
const DarkTheme = () => <></>;
export default DarkTheme;
light-theme.css
#import "~antd/dist/antd.css";
light-theme.jsx
import "./light-theme.css";
const LightTheme = () => <></>;
export default LightTheme;
use-theme.js A custom hook that different components can use -
import { useEffect, useState } from "react";
const DARK_MODE = "dark-mode";
const getDarkMode = () => JSON.parse(localStorage.getItem(DARK_MODE)) || false;
export const useTheme = () => {
const [darkMode, setDarkMode] = useState(getDarkMode);
useEffect(() => {
const initialValue = getDarkMode();
if (initialValue !== darkMode) {
localStorage.setItem(DARK_MODE, darkMode);
window.location.reload();
}
}, [darkMode]);
return [darkMode, setDarkMode];
};
theme-provider.jsx
import { lazy, Suspense } from "react";
import { useTheme } from "./use-theme";
const DarkTheme = lazy(() => import("./dark-theme"));
const LightTheme = lazy(() => import("./light-theme"));
export const ThemeProvider = ({ children }) => {
const [darkMode] = useTheme();
return (
<>
<Suspense fallback={<span />}>
{darkMode ? <DarkTheme /> : <LightTheme />}
</Suspense>
{children}
</>
);
};
change index.js to -
ReactDOM.render(
<React.StrictMode>
<ThemeProvider>
<App />
</ThemeProvider>
</React.StrictMode>,
document.getElementById("root")
);
now, in my navbar suppose I have a switch to toggle the theme. This is what it would look like -
const [darkMode, setDarkMode] = useTheme();
<Switch checked={darkMode} onChange={setDarkMode} />
you must create 2 components
the first one :
import './App.dark.css'
const DarkApp =() =>{
//the app container
}
and the second :
import './App.light.css'
const LightApp =() =>{
//the app container
}
and create HOC to handle darkMode like this :
const AppLayout = () =>{
const [isDark , setIsDark] = useState(false);
return (
<>
{
isDark ?
<DarkApp /> :
<LightApp />
}
</>
)
}
ANTD internally uses CSS variables for the "variable.less" file. We can override these variables to make the default variables have dynamic values at runtime.
This is one way it can be achieved:
app-colors.less file:
:root{
--clr-one: #fff;
--clr-two: #000;
--clr-three: #eee;
}
// Dark theme colors
[data-thm="dark"]{
--clr-one: #f0f0f0;
--clr-two: #ff0000;
--clr-three: #fff;
}
We can now override the default ANTD variables in antd-overrides.less file:
#import <app-colors.less file-path>;
#primary-color: var(--clr-one);
#processing-color: var(--clr-two);
#body-background: var(--clr-three);
We usually import the antd.less file to get the antd styles, We would change that to "antd.variable.less"(to use css variables).
index.less file:
#import "~antd/dist/antd.variable.less";
#import <antd-overrides.less file-path>;
Now we need to toggle the "data-thm" attribute on a parent container(body tag recommended) to change the set of CSS variables that get used.
const onThemeToggle = (themeType) => {
const existingBodyAttribute = document.body.getAttribute("data-thm");
if (themeType === "dark" && existingBodyAttribute !== "dark") {
document.body.setAttribute("data-thm", "dark");
} else if (themeType === "light" && existingBodyAttribute) {
document.body.removeAttribute("data-thm");
}
};
The above piece of code can be called on a Theme toggle button or during component mount.
In Ant's example one suggestion is to import your "dark mode" CSS or LESS file into your main style sheet.
// inside App.css
#import '~antd/dist/antd.dark.css';
Instead of trying to toggle stylesheets, the "dark" styles are combined with base styles in one stylesheet. There are different ways to accomplish this, but the common pattern will be:
have a dark-mode selector of some sort in your CSS
put that selector in your HTML
have a way to toggle it on or off.
Here is a working example:
https://codesandbox.io/s/compassionate-elbakyan-f7tun?file=/src/App.js
In this example, toggling the state of darkMode will add or remove a dark-mode className to the top level container.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [darkMode, setDarkMode] = useState(false);
return (
<div className={`App ${darkMode && "dark-mode"}`}>
<label>
<input
type="checkbox"
checked={darkMode}
onChange={() => setDarkMode((darkMode) => !darkMode)}
/>
Dark Mode?
</label>
<h1>Hello CodeSandbox</h1>
</div>
);
}
If darkMode is true, and the dark-mode className is present, those styles will be used:
h1 {
padding: 0.5rem;
border: 3px dotted red;
}
.dark-mode {
background: black;
color: white;
}
.dark-mode h1 {
border-color: aqua;
}
Ant Design newly start to support dynamic theme support. But its on experimental usage. You can find details on this link.
Conditional require won't block using previously required module. So, whenever your condition matches the require will available in your app. So, your both required module will be used. Instead of requiring them, insert stylesheet and remove to toggle between them:
const head = document.head
const dark = document.createElement('link')
const light = document.createElement('link')
dark.rel = 'stylesheet'
light.rel = 'stylesheet'
dark.href = 'antd.dark.css'
light.href = 'antd.light.css'
useEffect(() => {
const timer = setTimeout(() => {
if (darkMode) {
if (head.contains(light)) {
head.removeChild(light)
}
head.appendChild(dark)
} else {
if (head.contains(dark)) {
head.removeChild(dark)
}
head.appendChild(light)
}
}, 500)
return () => clearTimeout(timer)
}, [darkMode])
This package will help you to export and use theme vars without losing performance
Using less compiler in runtime:
https://medium.com/#mzohaib.qc/ant-design-dynamic-runtime-theme-1f9a1a030ba0
Import less code into wrapper
https://github.com/less/less.js/issues/3232
.any-scope {
#import url('~antd/dist/antd.dark.less');
}
I have a react component where I am trying to change the background color of the css when clicking the div.
I know you can set the color in the component, but I am using this component many times, and don't to make multiple component files with just a different color, and even if I did, I am curious besides the fact.
How can I access (or even console.log to figure it out on my own) the css file and its properties through the component? Thanks ahead of time.
If you want to keep all background-color styles in your .css/.scss file, you will need to have a good className strategy to link the styles to your components. Here is my suggestion:
styles.scss
.blue {
background-color: blue;
&.clicked {
background-color: red;
}
}
Container.js
import React from 'react';
import ClickableDiv from './ClickableDiv.js';
const Container = () => (
<ClickableDiv className="blue">
<p>This is my text.</p>
</ClickableDiv>
);
export default Container;
ClickableDiv.js
import React, { Component } from 'react';
class ClickableDiv extends Component {
constructor() {
super();
this.state = { clicked: false };
this.handleDivClick = this.handleDivClick.bind(this);
}
handleDivClick() {
this.setState({ clicked: true });
}
render() {
const divClassName = [this.props.classname];
if (this.state.clicked) divClassName.push('clicked');
return (
<div className={divClassName.join(' ').trim()} onClick={this.handleDivClick}>
{this.props.children}
</div>
);
}
}
export default ClickableDiv;
Rendered Markup
Unclicked:
<div class="blue"><p>This is my text.</p></div>
Clicked:
<div class="blue clicked"><p>This is my text.</p></div>
You can pass in the desired background color as a prop, and use internal state with an onClick handler.
Container.js
import React from 'react';
import ClickableDiv from './ClickableDiv';
const Container = () => (
<ClickableDiv backgroundColor="#FF0000">
<p>This is my text.</p>
</ClickableDiv>
);
export default Container;
ClickableDiv.js
import React, { Component } from 'react';
class ClickableDiv extends Component {
constructor() {
super();
this.state = {};
this.handleDivClick = this.handleDivClick.bind(this);
}
handleDivClick() {
const { backgroundColor } = this.props;
if (backgroundColor) this.setState({ backgroundColor });
}
render() {
const { backgroundColor } = this.state;
return (
<div style={{ backgroundColor }} onClick={this.handleDivClick}>
{this.props.children}
</div>
);
}
}
export default ClickableDiv;
Better to make an external css file and write your css code in that file and just import that one in index.html