antd overwriting styled components - css

I have a react project (which was not bootstrapped from CRA) which uses antd and styled components.
EDIT:
Components rendered 'under' a route do not apply styles from styled components.
I initially thought that antd, the ui framework I am using was overwriting the styled components styles but I discovered something interesting; If I add a styled component to the header component it works just fine but if I add a styled component to any component rendered on a route, the styles are not applied.
My main App component has the following structure:
import React, { Fragment } from 'react';
import { ConnectedRouter } from 'connected-react-router';
import { history } from '../store/config';
...
const App = () => {
return (
<ConnectedRouter history={history}>
<Fragment>
<Header />
<Routes />
</Fragment>
</ConnectedRouter>
);
};
For completeness, the routes component looks like this:
import React from 'react';
import { Route, Switch, withRouter } from 'react-router-dom';
import HomePage from '../components/pages/HomePage';
import EditorPage from '../components/pages/EditorPage';
export const Routes = () => {
return (
<Switch>
<Route exact path="/" component={withRouter(HomePage)} />
<Route exact path="/editor" component={withRouter(EditorPage)} />
</Switch>
);
};
export default Routes;
The example below is code I've added to the HomePage component.
package versions in use:
"antd": "^4.3.4",
"history": "^4.10.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.1.2",
"redux": "^4.0.5",
"styled-components": "^5.1.1",
END EDIT.
For some reason the styles from styled components are overwritten by antd unless I place the styles inline.
For example, in the following code snippet the border does not get applied. A super basic example but it demo's the point.
const HomePage = () => {
render(
<Container>
Hello
</Container>
);
};
const Container = styled.div`
border: 1px solid red;
`;
It renders like this:
Looking in dev tools the style doesn't even show up.
But if I add the style inline like this:
<Container style={{ border: '1px solid red' }}>
Boom! red border:
What am I missing??
Of course any help or suggestions is greatly appreciated!

I read the docs of styled-components and I think this is the problem.You should use style before render.
const Button = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0.5em 1em;
padding: 0.25em 1em;
${props => props.primary && css`
background: palevioletred;
color: white;
`}
`;
const Container = styled.div`
text-align: center;
`
render(
<Container>
<Button>Normal Button</Button>
<Button primary>Primary Button</Button>
</Container>
);
Look at the above example that appears on the page.

You can write styled like:
const Container = styled.div`
&& {
border: 1px solid red;
}
`

Related

Change styling of nested dom element of a custom react library UI component

I am using react-phone-input-2 library in my code-base. This component is used in conjuction with react-hook-forms and yup for field validation. Using their material.css file for styling and adding some custom CSS I have been able to modify its default look. For custom CSS I am using .css file like so:
phone-input.css
.react-tel-input .special-label {
background-color: transparent !important;
color: #009378 !important;
position: absolute;
top: 6px !important;
font-size: 12px !important;
left: 10px !important;
}
When the field validation fails, I have to toggle color of this ".special-label" classes color. I am not sure how to do that. I could not find an API which they expose for this special-label classes style. Github repo of phone-input.
Here is my phone-input code:
import React from 'react';
import PhoneInput from 'react-phone-input-2';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faPhone } from '#fortawesome/free-solid-svg-icons';
import { Controller } from 'react-hook-form';
import FormIcon from './FormIcon';
import 'react-phone-input-2/lib/material.css';
import './phone-input.css';
export default function FormPhoneInput({ error, validation }) {
return (
<div className={`relative inline-block ${error ? 'pb-4' : ''}`}>
<Controller
name="phone"
render={({ field }) => (
<PhoneInput
country="in"
placeholder="Phone"
name="phone"
countryCodeEditable={false}
defaultErrorMessage={error}
isValid={() => {
return error ? false : true;
}}
inputProps={{
required: true,
}}
inputStyle={{
width: '100%',
color: '#F2FBF7',
...(error
? { background: '#4D3230' }
: { background: '#004246' }),
border: 'none',
outline: 'none',
}}
{...field}
/>
)}
></Controller>
<FormIcon
icon={<FontAwesomeIcon icon={faPhone} />}
error={error}
validated={validation}
/>
</div>
);
}
Rendered DOM look like this: (react-tel-input wraps the whole component and special label is a child div)
Current UI looks like this, when validation is failed:

Styled Components - How to style a component passed as a prop?

I am trying to build this simple component which takes title and Icon Component as props and renders them. The icons I use here are third party components like the ones from Material UI.
option.component.jsx
import { Wrapper } from './option.styles';
function Option({ title, Icon }) {
return (
<Wrapper>
{Icon && <Icon />}
<h4>{title}</h4>
</Wrapper>
);
}
option.styles.js
import styled from 'styled-components';
export const Wrapper = styled.div`
display: flex;
color: grey;
&:hover {
color: white;
}
`;
// export const Icon =
I've organized all my styles in a separate file and I intend to keep it that way.
I want to style <Icon /> , but I don't want to do it inside Option Component like this.
import styled from 'styled-components';
import { Wrapper } from './option.styles';
function Option({ title, Icon }) {
const IconStyled = styled(Icon)`
margin-right: 10px;
`;
return (
<Wrapper>
{Icon && <IconStyled />}
<h4>{title}</h4>
</Wrapper>
);
}
What is the best way to style a component passed as a prop while maintaining this file organization?
I've looked through the documentation and I wasn't able find anything related to this. Any help would be appreciated.
You can do this in 2 ways:
1. As a SVG Icon (svg-icon):
option.styles.js as:
import styled from "styled-components";
import SvgIcon from "#material-ui/core/SvgIcon";
export const Wrapper = styled.div`
display: flex;
color: grey;
&:hover {
color: black;
}
`;
export const IconStyled = styled(SvgIcon)`
margin-right: 10px;
`;
And in your component, do like that:
import { Wrapper, IconStyled } from "./option.styles";
function Option({ title, Icon }) {
return (
<Wrapper>
{Icon && <IconStyled component={Icon} />}
<h4>{title}</h4>
</Wrapper>
);
}
const App = () => {
return (
<>
<Option title="title" Icon={HomeIcon}></Option>
<Option title="title" Icon={AccessAlarmIcon}></Option>
</>
);
};
2. As a Font Icon (font-icons):
Import material icons in <head>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
option.styles.js as:
import styled from "styled-components";
import Icon from "#material-ui/core/Icon";
export const Wrapper = styled.div`
display: flex;
color: grey;
&:hover {
color: black;
}
`;
export const IconStyled = styled(Icon)`
margin-right: 10px;
`;
And in your component, do like that:
import { Wrapper, IconStyled } from "./option.styles";
function Option({ title, icon }) {
return (
<Wrapper>
{icon && <IconStyled>{icon}</IconStyled>}
<h4>{title}</h4>
</Wrapper>
);
}
const App = () => {
return (
<>
<Option title="title" icon='star'></Option>
<Option title="title" icon='home'></Option>
</>
);
};

customize antd tooltip styles using styled components

I am trying to have custom width for antd tooltip component: Link to docs
How can this be done ?
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import { Tooltip } from "antd";
import styled from "styled-components";
const Styled = styled.div`
.ant-tooltip-inner {
color: yellow;
background-color: green;
width: 800px;
}
`;
ReactDOM.render(
<Styled>
<Tooltip title="prompt text">
<span>Tooltip will show on mouse enter.</span>
</Tooltip>
</Styled>,
document.getElementById("container")
);
The antd Tooltips docs gives you a hint for your issue. The Tooltip is added as div in the body by default, in fact your custom style won't work without any adaptions. Depending on your requirements you can use
GlobalStyle from Styled Components
Overwrite getPopupContainer from Antd Tooltip
GlobalStyle
As one workaround you can use the globalStyle
const GlobalStyle = createGlobalStyle`
body {
.ant-tooltip-inner {
color: yellow;
background-color: green;
width: 800px;
}
}
`;
ReactDOM.render(
<Tooltip title="prompt text">
<GlobalStyle />
<span>Tooltip will show on mouse enter.</span>
</Tooltip>,
document.getElementById("container")
);
Here is a CodeSandbox for this workaround.
getPopupContainer
From the Tooltip docs for getPopupContainer
The DOM container of the tip, the default behavior is to create a div
element in body
Here you can just pass the triggerNode to be the parent object and your styles are set as expected.
const Styled = styled.div`
.ant-tooltip-inner {
color: yellow;
background-color: green;
width: 800px;
}
`;
ReactDOM.render(
<Styled>
<Tooltip title="prompt text" getPopupContainer={(triggerNode) => triggerNode}>
<span>Tooltip will show on mouse enter.</span>
</Tooltip>
</Styled>,
document.getElementById("container")
);
Working CodeSandBox for using getPopupContainer.
The default behavior for DOM container of the tip is to create a div element in body. You can change it to create inside Tooltip element with getPopupContainer:
<Tooltip
getPopupContainer={(trigger) => {
console.log(trigger);
return trigger;
}}
title="prompt text"
>
With the code above you style .ant-tooltip-inner will work.
For more info, check this link -> Tooltip Antd API

Apply onHover styles to elements in MuiButton

I am using styled components and Material UI and I can't figure out how to add on hover styles the MuiButton children. I've searched online and followed some of the docs, but I cannot seem to get it to take. I have my jsx setup like so:
<StyledMuiButton onClick={() => ()}>
<Svg />
<MuiTypography color={Color.gray} variant="caption">
Text
</MuiTypography>
</StyledMuiButton>
and the styled component set up like so:
const StyledMuiButton = styled(MuiButton)`
&& {
& .MuiButton-label {
flex-direction: column;
}
&:hover ${MuiTypography} {
color: ${Color.primary};
}
}
`;
Can anyone point me in the correct direction
Here's an example showing a couple ways of targeting elements within a button:
import React from "react";
import Button from "#material-ui/core/Button";
import Typography from "#material-ui/core/Typography";
import DoneIcon from "#material-ui/icons/Done";
import styled from "styled-components";
const StyledButton = styled(Button)`
& .MuiButton-label {
display: flex;
flex-direction: column;
}
&:hover {
color: red;
.MuiSvgIcon-root {
background-color: blue;
}
.MuiTypography-root {
color: green;
&:nth-of-type(2) {
color: purple;
}
}
}
`;
export default function App() {
return (
<div className="App">
<Button>Default Button</Button>
<StyledButton>Styled Button</StyledButton>
<StyledButton>
<DoneIcon />
<span>Styled Button</span>
<Typography>Typography 1</Typography>
<Typography>Typography 2</Typography>
</StyledButton>
</div>
);
}
This leverages the global class names applied to the elements which are documented in the CSS portion of the API page for each component (for instance the Typography documentation is here: https://material-ui.com/api/typography/#css). As a general rule the top-most element within a Material-UI component can be targeted via MuiComponentName-root (e.g. MuiTypography-root for Typography).

How to override react-bootstrap colors?

I was looking up how to change it but none of the solutions seemed to work for me.
I want to override the color of a react-bootstrap button.
This solution as below works just fine and is exactly what i wanna do:
<Button
block
style={{backgroundColor: '#0B0C10', borderColor: '#45A293', color: '#45A293', borderRadius: '100px'}}
>
sample text
</Button>
But i don't wanna rewrite it each time i use button so i would like to have solution with css, I've tried using this:
.custom-button {
background-color: #1F2833;
border-color: #45A293;
border: 3px solid-transparent;
color: #45A293;
border-radius: 100px;
}
And then passing it in className like like so className="custom-button" but it doesn't really work.
I am using Button from react-bootstrap
import {Button} from "react-bootstrap";
Styles from bootstrap
import 'bootstrap/dist/css/bootstrap.min.css';
Using versions as below:
"react-bootstrap": "^1.0.0-beta.5",
"bootstrap": "^4.3.1",
Styles applied using the style="" attribute of HTML elements are more specific than styles applied through classes, which is why your first solution worked. Appending !important at the end of styles is one way of overriding other styles which are more specific than .custom-button class.
One quick solution that comes to my mind, that will ensure that you don't repeat yourself, is storing the styles in an object and importing them from a file.
styles.js
const styles = {
customButton: {
backgroundColor: '#0B0C10',
borderColor: '#45A293',
color: '#45A293',
borderRadius: '100px'
}
};
export default styles;
Component.jsx
import { styles } from './styles.js'
<Button
block
style={styles.customButton}
>
sample text
</Button>
Otherwise you would have to play with attaching ID's or construct more specific css selectors.
Add a bg or btn
.bg-custom-button {
background-color: #1F2833;
border-color: #45A293;
border: 3px solid-transparent;
color: #45A293;
border-radius: 100px;
}
Got mine working like that
Then in the bg="custom-button"
I am unsure if this effect is intended or not but the easiest way that I have found to override React Bootstrap css is to use Material ui withStyles. Here is an example.
import React from 'react';
import { withStyles } from '#material-ui/styles';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import ButtonGroup from 'react-bootstrap/ButtonGroup';
import Button from 'react-bootstrap/Button';
const styles = {
logoContainer: {
position: 'fixed',
},
rowStyles: {
marginBottom: '10px',
},
button: {
border: '3px inset #ffc107',
borderRadius: '50%',
width: '55px',
height: '55px',
fontFamily: 'fangsong',
fontSize: '1em',
fontWeight: '700',
color: 'white',
backgroundColor: 'rgb(0,0,0, 0.5)',
}
}
const Logo = (props) => {
const logoStyles = props.classes;
return (
<div>
<Container container='true' className={logoStyles.logoContainer}>
<ButtonGroup >
<Col>
<Row className={logoStyles.rowStyles}>
<Button onClick={{}} className={logoStyles.button}>BS</Button>
</Row>
</Col>
</ButtonGroup>
</Container>
</div>
);
}
export default withStyles(styles)(Logo);
Hope this helps...
You can use the "bsPrefix" prop which allows to override the underlying component CSS base class name.
bsPrefix="custom-button"

Resources