Overriding styles in semantic ui react

Specificity is king. Only time would need to use !important would be when inline style is present and the library does not expose a way to toggle the property off in some way (poor architecture choice).

The following list of selector types increases by specificity:

Type selectors (e.g., h1) and pseudo-elements (e.g., ::before).

Class selectors (e.g., .example), attributes selectors (e.g., [type="radio"]) and pseudo-classes (e.g., :hover).

ID selectors (e.g., #example).

https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity

Take a look at the first UI Button for Semantic UI here, is comprised of the following HTML:

<button class="ui button">Click Here</button>

CSS is attached via semantic.min.css:

.ui.button {
    cursor: pointer;
    display: inline-block;
    min-height: 1em;
    outline: 0;
    border: none;
    vertical-align: baseline;
    background: #e0e1e2 none;
    color: rgba(0,0,0,.6);
    font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;
    margin: 0 .25em 0 0;
    padding: .78571429em 1.5em .78571429em;
    text-transform: none;
    text-shadow: none;
    font-weight: 700;
    line-height: 1em;
    font-style: normal;
    text-align: center;
    text-decoration: none;
    border-radius: .28571429rem;
    -webkit-box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34,36,38,.15) inset;
    box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34,36,38,.15) inset;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    will-change: '';
    -webkit-tap-highlight-color: transparent;
}

To override say, the font color, all we have to do is write a selector that is more specific than this selector. We can achieve this by combining their two class selectors (equally specific) with a type selector (additional specificity).

This would look like:

button.ui.button {
  color: red;
}

Now since button.ui.button is more specific in describing the location of the element in the page (DOM), than say just .ui.button, this signals to the browser that this style should override the previous declaration. This is a common way to customize a theme.

Great docs here: https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS

.ui.button {
    cursor: pointer;
    display: inline-block;
    min-height: 1em;
    outline: 0;
    border: none;
    vertical-align: baseline;
    background: #e0e1e2 none;
    color: rgba(0,0,0,.6);
    font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;
    margin: 0 .25em 0 0;
    padding: .78571429em 1.5em .78571429em;
    text-transform: none;
    text-shadow: none;
    font-weight: 700;
    line-height: 1em;
    font-style: normal;
    text-align: center;
    text-decoration: none;
    border-radius: .28571429rem;
    -webkit-box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34,36,38,.15) inset;
    box-shadow: 0 0 0 1px transparent inset, 0 0 0 0 rgba(34,36,38,.15) inset;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease;
    transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease;
    will-change: '';
    -webkit-tap-highlight-color: transparent;
}

button.ui.button {
  color: red;
}
<button class="ui button">Click Here</button>

Actually you should never use !important unless you really REALY have too. Apart from making you styles look very ugly, its a very bad practice to make all your styles !important

Since you mentioned CRA, which supports SCSS Modules, I can tell you that there is a third option which in my opinion is a bit nicer.

Here it goes in 3 easy steps:

1. Set an id somewhere high in the hierarchy. I do it in the public/index.html on the body tag:

// public/index.html

...
  <body id='app'>
...

2. Create a SCSS module file and wrap all your classes in a :global(#app)

// src/page.module.scss

:global(#app) {
  .container {
    padding: 2rem;
  }
  .button {
    font-size: 3em;
  }

}

3. Import the styles and pass them to the semantic components

// src/page.jsx

import React from 'react';
import { Button, Container } from 'semantic-ui-react';
import styles from './page.module.scss'

const Page = () => (
  <Container className={styles.container}>
    <Button className={styles.button} />
  </Container>
)

The reason this works is because the output from the page.module.scss SCSS Module will be compiled to this:

#app .page_container_2oYQ {
  padding: 2rem;
}

#app .page_button_2oYQ {
  font-size: 3em;
}

As you can see it will add the #app id selector before the modularised class name, which will increase the specificity of your selectors, which in turn will override the semantic-ui ones.


When you have CSS file from semantic ui, bootstrap, angular material ui, etc, just to name a few. When you want to override the css for any element, the order in which you render or place your css file in your html determines the precedence.

For your css file to override some other css file, list yours at the bottom. Of course ensure your css selector targets the element your want to override.

An picture is worth a 1000 words

Assuming you want to override this below from semantic ui

<!-- from semantic-ui.min.css file or cdn -->
@media only screen and (min-width: 1200px) {
  .ui.container {
    max-width: 768px !important;
    margin-left: auto !important;
    margin-right: auto !important;
  }
}

<!--override in my-custom-ui.css file --->

@media only screen and (min-width: 1200px) {
  .ui.container {
    max-width: 360px !important;
    margin-left: 10px !important;
    margin-right: 10px !important;
  }
}

<!--this is where precedence is set, the last css file has the highest precedence-->
<!DOCTYPE html>
<html lang="en">
<head>
 <title>my title</title>
 <meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/semantic-ui/dist/semantic.min.css"
    />

<!-- place your css file containing css overridden for semantic ui elements or other css at the bottom -->
<link rel="stylesheet" href="my-custom-ui.css" />
</head>
<body>
<header>
 My header
</header>
<content>
 My content
</content>
<footer>
 My footer
</footer>
</body
<script/>
</html>