How to access inner elements of external components - reactjs

I have an external Select react component which in turn render li tags.
I want to style all li except the first one with margin-left of 20px;
Below is the code:
const StyledSelect = styled(Select)`
li {
margin-left: 20px;
}
`
Any idea why this is not working or another way to do this?

This should work, but depending on how the external Select has the styles applied they might have a higher specificity and are still overriding the styles you applied. (see this article for a primer on how specificity works)
Without knowing which Select component you're using it's a bit hard to debug, but I'm assuming it uses inline styles (i.e. the style prop) which have a very high specificity and would thus override your applied styles.
There's two ways to bump specificity of your styles, both of which are not recommended if the external component doesn't use inline styles.
The first way to bump specificity is to use !important:
const StyledSelect = styled(Select)`
li {
margin-left: 20px!important;
}
`
In some cases that might not suffice, and it's also pretty tedious once you have more properties you need to forcibly override. A better way, but still not recommended way too it is to use the class hack: (notice the ampersands)
const StyledSelect = styled(Select)`
&&& li {
margin-left: 20px;
}
`
What styled-components does here is replace each of these & with the generated class, meaning the resulting CSS will look something like this:
.sc-asdf123.sc-asdf123.sc-asdf123 li {
margin-left: 20px;
}
These three classes massively bump the specificity of the styles within the block. That should do the trick!
To not style the first child you can use the first-child together with the not pseudo selector:
const StyledSelect = styled(Select)`
&&& li:not(:first-child) {
margin-left: 20px;
}
`

You could use CSS pseudo-classes:
const StyledSelect = styled(Select)`
li:not(:first-child) {
margin-left: 20px;
}
`
Read more about CSS pseudo-classes: https://developer.mozilla.org/en/docs/Web/CSS/Pseudo-classes

Related

scss to styled-components conversion warning

In a project, I was using SCSS, where I wrote this code and it works like a charm:
.container {
padding: 0 1rem;
.container {
padding: 0;
}
}
Now, I am starting another project using styled-components. So, there I am writing these styles:
const Container = styled.div`
padding: 0 1rem;
${Container} {
padding: 0;
}
`;
Now I get a warning from compiler saying:
Container was used before it was defined.
I want to ignore this warning without making any changes to eslint-file or disabling eslint for the line itself. I also don't want to use var instead of const.
Also, I am not willing to use a class on the div and then use it again here. (I would consider this as the last option if I do not find any better way of doing this).
Is there any better way that I can change this code to ignore this warning?
If I understand your question/issue it seems you want to reference the same container component. Use & to refer back to the main component.
Using pseudoelements, pseudoselectors, and nesting
const Container = styled.div`
padding: 0 1rem;
& {
padding: 0;
}
`;

Force ExpansionPanel to be expanded, when printing

I am using an ExpansionPanel,
where I control the expanded state based on some conditions.
Although, I want the ExpansionPanel to be always expanded, when I am printing (window.print()).
What I intuitively wanted to try was:
//...
const isPrinting = useMediaQuery("print")
const controlledExpanded = useSomeMethodToControlExpanded()
const expanded = isPrinting || controlledExpanded
return (
<ExpansionPanel expanded={expanded}>
{/*...*/}
</ExpansionPanel>
)
Although this won't work because of a bug in browsers:
Maybe somehow override the global styling would help, but I cannot figure out how.
Any ideas?
You can use #media print in your css:
#media print {
div.MuiCollapse-container.MuiCollapse-hidden {
min-height: auto !important;
height: auto !important;
visibility: visible !important;
}
}
No need for anything in the react component

How to do SSR for responsive apps without knowing the device's screen size upfront?

I want to SSR my app for my users.
But my app code uses a useEffect to detect what is the size of the user's screen width, and only then the App is rendered.
Something like:
App.js
// THE LAYOUT INITIAL STATE IS NULL
useEffect(() => {
// CHECK FOR window.innerWidth AND DECIDE LAYOUT
// UPDATE LAYOUT STATE
});
return(
layout && <AppComponents> // IF THERE IS NO LAYOUT, NOTHING IS RENDERED
);
Component.js
// I SERVE THE LAYOUT THROUGH CONTEXT AND I ACCESS IT INSIDE OF THE COMPONENTS
const layout = useLayout();
return(
layout === "MOBILE" ? ComponentMobile : ComponentDesktop
);
QUESTION
I cannot rely on a code inside of a useEffect to render stuff on the server. So, somehow I need to "decide" which layout to use for the first and only render on the server.
So my options, at least the ones I've though of so far, are:
OPTION #1
Try to guess the user's device screen size, and render something that might not be optimal for their screen size.
Because right now, the CSS styles that I'm rendering depend on the user's screen size.
OPTION #2
Move entirely to media queries to handle responsiveness, so the CSS will always be the same and it will adapt automatically to whatever size of screen is being used.
So far I haven't been using media queries at all. All my layout decisions are made during the render, and all the component render the styles based on the layout that was decided from App.js state.
What is the best way of handling this? Is there a best practice for this?
NOTE:
I am using styled-components, so this is basically what I do:
This is a crude example, but that's the idea.
// THIS IS MUCH EASIER TO WRITE THAN A BUNCH OF MEDIA QUERIES (IMO)
const Styled_DIV = styled.div`
font-size: ${props =>
props.layout === "MOBILE" ? "16px"
: props.layout === "TABLET" ? "18px"
: "20px"
};
`;
Great, you're already using styled-components. Adding media queries is now trivial and actually more straightforward (IMO) than your suggested method.
In general, configuring layout with CSS performs better than with JS. And with SSR, like you said, the server can't determine the screen size yet with JS and useEffect.
If you're mobile first, you can write the above logic with media queries like this:
const Styled_DIV = styled.div`
font-size: 16px;
#media (min-width: 768px) {
font-size: 18px;
}
#media (min-width: 1024px) {
font-size: 20px;
}
`
I wrote a helper object export so I don't have to remember the pixel sizes or even the syntax for media queries:
export const size = {
tablet: 768,
desktop: 1024,
}
export const device = {
tablet: `#media (min-width: ${size.tablet}px)`,
desktop: `#media (min-width: ${size.desktop}px)`,
}
So now I just have to write:
const Styled_DIV = styled.div`
font-size: 16px;
${device.tablet} {
font-size: 18px;
}
${device.desktop} {
font-size: 20px;
}
`
Since device is an exported object, my VSCode editor automatically helps me import it when I start typing.

Overwriting global CSS style in modules is not working

I'm having a problem with overwriting CSS styles using composing in modules.
My current setup:
I have a thirdparty grid library file which I insert into my application in the entry JS file:
import './css/thirdparty/file.css';
I'm also using CSS modules for my components like this:
import styles from './component.module.css';
const Component = () => {
// component code omitted
// in render
<div className={styles.col14}></div>
In webpack config, I have two rules setup to load the file.css using plain css-loader and the *.module.css files using css-loader with modules.
All of these files are loaded correctly and the styles are all present. Here's the problem:
file.css contains:
.col-1-4 /* and all other col-1-* variations*/ {
float: left;
min-height: 1px;
padding-right: 20px;
}
.col-1-4 {
width: 25%;
}
component.module.css contains:
.col14 {
composes: col-1-4 from global;
padding-right: 0;
}
Current output of the component:
<div class="col14__3bA8W col-1-4">
So the style is supposedly overwritten, but what I see in the browser is that the padding-right is still 20px. It seems to only happen when I try to compose from a global style, because if I compose two classes from the same component CSS file, it works as expected.
Does anyone know why this is not working?
You can try with
.col14 {
composes: col-1-4 from global;
padding-right: 0!important;
}

How can I select all children of an element except the last child?

How would I select all but the last child using CSS3 selectors?
For example, to get only the last child would be div:nth-last-child(1).
You can use the negation pseudo-class :not() against the :last-child pseudo-class. Being introduced CSS Selectors Level 3, it doesn't work in IE8 or below:
:not(:last-child) { /* styles */ }
Make it simple:
You can apply your style to all the div and re-initialize the last one with :last-child:
for example in CSS:
.yourclass{
border: 1px solid blue;
}
.yourclass:last-child{
border: 0;
}
or in SCSS:
.yourclass{
border: 1px solid rgba(255, 255, 255, 1);
&:last-child{
border: 0;
}
}
easy to read/remember
fast to execute
browser compatible (IE9+ since it's still CSS3)
Nick Craver's solution works but you can also use this:
:nth-last-child(n+2) { /* Your code here */ }
Chris Coyier of CSS Tricks made a nice :nth tester for this.
When IE9 comes, it will be easier. A lot of the time though, you can switch the problem to one requiring :first-child and style the opposite side of the element (IE7+).
Using nick craver's solution with selectivizr allows for a cross browser solution (IE6+)
There is a:not selector in css3. Use :not() with :last-child inside to select all children except last one. For example, to select all li in ul except last li, use following code.
ul li:not(:last-child){ }
If you're using it within the nesting of the parent then the easiest way is:
&:not(:last-child){
....
}
Example:
.row { //parent
...
...
...
&:not(:last-child){
....
}
}
Using a more generic selector, you can achieve this as seen below
& > *:not(:last-child) {/* styles here */}
Example
<div class="parent">
<div>Child one</div>
<div>Child two</div>
</div>
This will capture all the child DIV in the parent
to find elements from last, use
<style>
ul li:not(:last-child){ color:#a94442}
</style>
Nick Craver's solution gave me what I needed but to make it explicit for those using CSS-in-JS:
const styles = {
yourClass: {
/* Styles for all elements with this class */
'&:not(:last-child)': {
/* Styles for all EXCEPT the last element with this class */
},
},
};
.nav-menu li:not(:last-child){
// write some style here
}
this code should apply the style to all except the last child

Resources