I am following these docs in order to style a material ui component (Paper) within a component (Menu) I am using.
I am using CSS modules to style my components (with Webpack as a bundler) :
// menu.js
import React from 'react';
import { StyledEngineProvider } from '#mui/material/styles';
...
import styles from './styles.module.css';
import Menu from '#mui/material/Menu';
import MenuItem from '#mui/material/MenuItem';
const MyMenu = (props) => {
...
return (
<StyledEngineProvider injectFirst>
<div id="my-menu">
<Button id="button-react-component" onClick={handleClick}>
My Menu
</Button>
<Menu
id="menu-react-component"
...
className={styles.menu}
>
<MenuItem ...>
<span> Example 1 <span>
</MenuItem>
</Menu>
</div>
);
}
// styles.module.css
.menu {
color: white;
}
.menu .MuiPaper-root {
background-color: red
}
// Also tried :
.menu .root {
background-color: red
}
My goal is to have the MuiPaper component have a given background-color. MuiPaper is a component that comes from the Menu component, but I am not using MuiPaper directly as I am only declaring the parent (<Menu>).
Ideally I want to use .css files for styling. I use webpack to bundle my css files into modules.
Here's what I see in my browser :
Notice how the background-color "red" is not applied on that last screenshot.
Thanks :)
CSS modules can't override a style from another CSS module (or elsewhere). There's a few ways to get around this:
Add another class specifically for the .menu paper, e.g. .menuPaper, and add it via PaperProps on the Menu component:
.menuPaper {
background-color: blue;
}
<Menu
id="menu-react-component"
...
className={styles.menu}
PaperProps={{ className: styles.menuPaper }}
>
Add the :global selector to your css selector:
.menu :global .MuiPaper-root {
background-color: red;
}
CSS modules work by "modulifying" CSS classnames by adding a unique ID to the end of them. The :global selector can be used to disable this and preserve the classname instead.
The difference between these two methods is that if you had multiple Menu components in your MyMenu component, using the :global method would give all the Menu instances inside of MyMenu the same background. With the PaperProps method only specific Menus with PaperProps={{ className: styles.menuPaper }} would get the styles applied.
css-loaderdocs: https://github.com/webpack-contrib/css-loader#scope
MUI Menu docs: https://mui.com/api/menu/#props (also see Popover component)
Related
Currently I have the following code:
FormInput.jsx:
import './FormInput.scss';
const FormInput = ({ label, ...otherProps} ) => {
const { value } = otherProps;
return (
<div className="group">
<input className="formInput" {...otherProps} />
{label && (
<label
className={`${value.length ? 'shrink' : ''} formInput-label`}
>{label}</label>
)}
</div>
)
};
export default FormInput;
In FormInput.scss:
.formInput-label {
transition: 300ms ease all;
position: absolute;
font-size: 18px;
left: 5px;
top: 10px;
&.shrink {
top: -14px;
}
}
What I'm confused about is that the targeted class of the label in FormInput.jsx should compile to:
.shrink .formInput-label
But the one in the SASS file will compile to:
.formInput-label.shrink
My question is how does the correct styling still get applied if the class targeting in the JSX and SASS files aren't the same? The JSX has the classes in reverse order and a space in between.
The class attribute (or className in JSX) defines a list of classes. The syntax for classes is different in HTML and in CSS, but the order of classes on the same element does not matter in either.
JSX renders to HTML, so it renders as class="shrink formInput-label", which defines the list of classes ["shrink", "formInput-label"] and is compatible with the CSS selector .shrink.formInput-label.
Also, a CSS selector such as .shrink would match the element as well (just with a lower specifity rating), because it matches one of the classes in the list.
I'm using Input from Semantic UI in order to create a search input:
import React from 'react';
import { Input } from 'semantic-ui-react';
export default ({ placeholder, onChange }) => {
return (
<Input
icon="search"
icon={<img src={searchIcon} />}
iconPosition="left"
placeholder={placeholder}
onChange={onChange}
/>
);
};
It works and looks good.
The problem is that I need to change its icon with an svg image. So the svg is imported in the file and used like this:
import React from 'react';
import { Input } from 'semantic-ui-react';
import searchIcon from '../../assets/icons/searchIcon.svg';
export default ({ placeholder, onChange }) => {
return (
<Input
icon={<img src={searchIcon} />}
iconPosition="left"
placeholder={placeholder}
onChange={onChange}
/>
);
};
The problem is that it puts the icon outside of the input and on the right side of it.
It should be inside the input and on the left part.
There were no styling changes after the svg was added, why isn't it in the same position as the original icon?
Most likely semantic-ui adding special styles when we add some icon by attribute "icon". Semantic-ui-react doesn't support custom icons. :,(
In the type declaration we can read:
/** Optional Icon to display inside the Input. */icon?: any | SemanticShorthandItem<InputProps>
My proposition: add some styles to CSS, like me in the sandbox
.input {
position: relative;
width: fit-content;
display: flex;
justify-content: center;
align-items: center;
}
img {
position: absolute;
right: 5px;
width: 10px;
}
I got it working by passing a custom component where the svg image is wrapped by an i tag that has a an icon class:
const CustomIcon = (
<i className="icon">
<img width={38} height={38} src={searchIcon} />
</i>
);
const App = () => {
return (
<Input icon={CustomIcon} iconPosition="left" placeholder="placeholder" />
);
};
The benefit to this approach is that you can change the iconPosition without it breaking the styling with this approach.
To give more context the icon getting displayed at the right position is due to the styles applied to this selector: .ui.icon.input>i.icon. Because it expects an i tag the styles won't be applied if you don't wrap the image between i tags.
I'm new to styled-components and I'm bit confused.
Can we display something or add functionality to styled-compoentns.
OR styled-components is component that we can apply css only
styled-components is primarily intended to apply css.
So typically you would use wrapper components that provide the content and use the components obtained from styled-components for decoration.
Once in a while, I have found it useful to use the .attrs constructor to pass children when
the content is very specific to the component.
const ResourceMissingError= styled.div.attrs({
children: 'This resource could not be found'
})`color: red`;
render(<ResourceMissingError />);
Can we display something or add functionality to styled-components?
Yes, styled components are usable as any native component would be. So just as HTML's <button> can be used to display something, you can use a styled button to do so. See below.
Similarly, you can add functionality as you would in a native component, by listening to click events, for instance. The demo below "adds" functionality to the ColorfulButton by handling its click event.
See also how the color is passed as a prop to the ColorfulButton via mycolor="green":
const ColorfulButton = styled.button`
display: inline-block;
color: ${props => props.mycolor || "blue"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
display: block;
`;
class TodoApp extends React.Component {
constructor(props) {
super(props)
this.state = { text: "Learn JavaScript (click me)", done: true }
}
handleClick = e => {
this.setState({...this.state, done: !this.state.done});
}
render() {
return (
<div>
<ColorfulButton onClick={this.handleClick} mycolor="green">{this.state.text}</ColorfulButton>
<br />
{this.state.done ? 'Yes' : 'No'}
</div>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>
<div id="app"></div>
You can make a CSS file and import it in your different components like making class in CSS and use that class in your component as className="". Also, you can refer inline CSS like this way style={{}} make sure the properties name like font-size will be written in fontSize in React inline CSS. Every CSS property that have a dash in the middle of the property name, the dash will be removed and the next letter after dash will be capitalized and also the property value will be in double or single quotation.
I'm using React with SASS and CSS Modules. How can I style the children component without passing a new ClassName or something like that. For Ex.
I want to position or do some styles over the child components, without having to give a specific class, just like when you do p span just for example, all the spans would be the childrencomponent, and I just want to do some styling referencing all the children component in the parent. But as the class is compiled, I don't know how to reference those children.
//ParentComponent.js
Import Styles from 'ParentComponent.scss';
Import Child from 'ChildComponent';
Import ChildB from 'ChildComponentB';
...
return(
<div>
<ChildB />
<Child />
<Child />
</div>
);
//ParentComponent.scss (?)(?)
.child {...}
Here how do I reference the Child components only without passing down a ClassName for example, or without importing the ChildComponent's SASS file in order to get reference to the component class.
//ChildComponent.js
Import Styles from 'ChildComponent.scss';
...
return(
<div classNames={Styles.child}></div>
);
//ChildComponent.scss
.child {...}
There is multiple approach for this, with and without drawbacks.
Wrap each child in a div
This first one is to wrap each of your child components in a div and then add a class on it which then you can reference in your stylesheet:
return(
<div>
<div className={style.child}><ChildB /></div>
<div className={style.child}><Child /></div>
<div className={style.child}><Child /></div>
</div>
);
Pass the className as props
You can pass the class name as props and then add this props to any tag you want in your Child component. On the other hand, you have to do this for every components that you would like to have a class.
return(
<div>
<ChildB className={style.child}/>
<Child className={style.child}/>
<Child className={style.child}/>
</div>
);
//ChildComponent.js
Import Styles from 'ChildComponent.scss';
...
export default ({ className }) =>
<div className={`${Styles.child} ${className}`}></div>
Use the CSS child combinator
In your parent stylesheet, you can use the direct children selector > to select any direct children. You can also combine this operator with the star operator, but be careful with this one since it may slow the browser if used to frequently on a page
If we assume all your Child component is a div:
/* ParentComponent.scss */
.parent > div {
}
Or if you don't how of what Child are made of
/* ParentComponent.scss */
.parent > *{
}
Custom properties (--*): CSS variables could be an option if you have control over those child components.
Firstly, define child style with CSS variables, such as
.some-selector {
/* '--custom-var-name' is the css variable name, while 'white' is the default value */
background-color: var(--custom-var-name, 'white');
}
Then define --custom-var-name in parent components at any level.
<Parent style={{ '--custom-var-name': 'black' }}>
<Child />
</Parent>
or
<GrandParent style={{ '--custom-var-name': 'black' }}>
<Parent>
<Child />
</Parent>
</GrandParent>
I have a react component that is wrapped up in div:
AccountLogin.jsx:
import './AccountLogin.css';
export default observer(() => (
<div className="content">
Something here
</div>
));
AccountLogin.css:
.content {
color: blue;
background-color: blue;
margin: 500px;
}
But the css doesn't apply to my rendered component AccountLogin.
Any ideas why that could happen?
Looking at rfx-stack source, I can see that files suffixed with .global.css are imported in global scope where as others are imported as css-modules.
So you can either rename your file to AccountLogin.global.css or use the imported class name:
import styles from './AccountLogin.css';
Within component:
<div className={styles.content}>...</div>