I have a Playground here: https://codesandbox.io/s/736v9vjzw1
const Something = ({ classes, children, variant }) => {
return (
<div className={classes.someThing}>
<p> I'm some thing </p>
<SomeOtherThing />
<SomeOtherThing> I have some children </SomeOtherThing>
<SomeOtherThing> I have some children </SomeOtherThing>
<SomeOtherThing> I have some children </SomeOtherThing>
</div>
);
};
const styles = {
someThing: {
color: "green",
border: "solid 2px black",
margin: 30,
"& $someOtherThing": {
backgroundColor: "pink" // Doesn't work
},
"& p": {
fontWeight: "bold" //This works but is too broad
}
}
};
I have a situation here, where I want to style all the SomeOtherThing
s inside my SomeThing
.
I can use & p
selector to select the p
element - but I don't like this. It would style any random p
s I have around - and I don't want to have to look inside the component definition to find what it's top level element is.
How can I do this? Something like & SomeOtherElement
.
The real world application of this, is that in some places I want have SomeOtherElement
be displayed block
and other places inline-block
.
I would extend the SomeOtherThing
component to accept a className and add it to the div
if present. This will also work on a production setup, where the class names is minified to e.g. .t-0-root
.
Here is a forked playground: https://codesandbox.io/s/zlzx277zzm which shows how to use it.
const SomeOtherThing = ({ classes, children, className }) => {
return (
<p className={`${classes.someOtherThing} ${className && className}`}>
I'm another thing {children}
</p>
);
};
I would most likely use the package classnames
to conditionally render the class name instead of string interpolation.
const Something = ({ classes, children, variant }) => {
return (
<div className={classes.someThing}>
<p> I'm some thing </p>
<SomeOtherThing />
<SomeOtherThing className={classes.someOtherThing}>
I have some children
</SomeOtherThing>
<SomeOtherThing className={classes.someOtherThing}>
I have some children
</SomeOtherThing>
<SomeOtherThing className={classes.someOtherThing}>
I have some children
</SomeOtherThing>
</div>
);
};
const styles = {
someThing: {
color: "green",
border: "solid 2px black",
margin: 30
},
someOtherThing: {
backgroundColor: "pink"
}
};
It's so simple, in your someThing
CSS codes select the p
elements with class someOtherThing
class name and use not()
CSS operation for p
in top level, see following code:
const styles = {
someThing: {
color: "green",
border: "solid 2px black",
margin: 30,
"& [class*='SomeOtherThing']": {
backgroundColor: "pink" //
},
"& :not([class*='SomeOtherThing'])": {
fontWeight: "bold" // Just for top level p
}
}
};
and
const SomeOtherThing = ({ classes, children }) => {
return (
<p className={classes.root}> I'm another thing {children} </p>
);
};
CodeSandBox
The way that this works, is that by giving SomeOtherThing
any jss class, it's going to render the dom element as something like:
<p class="SomeOtherThing-root-0-1-2"> I'm another thing I have some children </p>
which the [class*='SomeOtherThing'
] attribute selector will match on.
You should note that this selector will apply to any deeper nested SomeOtherThing
s as well.
One problem with the "cascading" aspect of CSS is that it sort of breaks React's component model. But in React you can always create a wrapper or higher-order component that returns another with some predefined props, kind of like a factory function:
const Something = props => {
return (
<div className={props.className}>
// ...
</div>
)
}
const SomethingInline = props => {
return <Something className='display-inline' {...props} />
}
const SomethingBlock = props => {
return <Something className='display-block' {...props} />
}
const App = () => {
return (
<div>
<SomethingInline />
<SomethingBlock />
<SomethingBlock> I have children </SomethingBlock>
</div>
)
}
Instead of using the &
selector to define your style, create a class that only applies to these specific versions of your component. In this way, the global scope of CSS is avoided and you can create these sort of declarative components that describe their own style, but don't require you to explicitly pass a class name.