** For simplicity's sake I am not going to include all the Typescript stuff in my code examples here, so please just roll with it.
I'm using Semantic UI React as a UI component/styling framework for my SPFx webpart.
I have a button component that uses the Semantic UI Button component. Semantic UI adds its own classes ui button
to its button component. I want to apply some extra styling to my button, so I added my own custom class.
MyButton.module.scss
.myButton {
margin-top: 1em;
}
MyButton.tsx
import * as React from 'react';
import { Button } from 'semantic-ui-react';
import styles from './MyButton.module.scss';
export default class MyButton extends React.Component {
public render() {
return (
<Button className={styles.myButton} />
);
}
}
What ends up getting rendered in the HTML is
<button class="ui button myButton_123456"></button>
however, the extra styling I want added does not get applied because the Semantic UI CSS uses a selector of .ui.button
, and while I can see the that the browser recognizes that my class/style is there, it only recognizes the style as applying to the selector .myButton_123456
, so the default Semantic CSS has greater specificity, and my style is ignored.
Now if I were dealing with regular CSS, I know that I could define my custom style like this:
.ui.button.myButton {
margin-top: 1em;
}
and my style would have more specificity and override the default Semantic styling.
However, if I put that in the SCSS module file, what I end up seeing is that those classes all get split up and are available as separate properties on the style
object imported into my component.
If I just use my custom style alone, as I did originally, the HTML gets rendered the same, but in the browser CSS tools, I no longer see my class as a single class that's getting overridden by Semantics double class selector. It's just not there anymore.
And if I try something like
<Button className={`${styles.ui} ${styles.button} ${styles.myButton}`} />
then the HTML ends up like
<button class="ui button ui_123456 button_654321 myButton_987654"></button>
Now, in that case I win the specificity battle by having a triple-class selector, but it happens by inadvertently creating two new classes, which seems unnecessary.
So how can I structure things so that the browser ends up seeing
.ui.button.myButton_123456 {
margin-top: 1em;
}
and correctly overrides the default Semantic styling by using Semantics own classes and one single new custom class?
Thanks to @theChrisKent for the answer, I've now learned a bit about :global
and :local
when using CSS modules.
Just wanted to add that the solution was not exactly as in the posted answer. Trying to do
.myButton {
:global {
&.ui.button {
margin-top: 1em;
}
}
}
gave me build errors saying "missing whitespace after :global", and looked like it was trying to construct the CSS like this:
.myButton :global.ui.button {
margin-top: 1em;
}
The way I was able to get it to work was by constructing the SASS like this:
.myButton:global(.ui.button) {
margin-top: 1em;
}
which comes across in the browser like
.myButton_123456.ui.button {
margin-top: 1em;
}
which is exactly what I was looking for.