Radix UI Styling Not Applying
Intro
If you are experiencing some (or all of) the following symptoms this post will help you address it.
- You have recently added some Radix UI components (and new styles for them) to your project.
- You aren't experiencing any issues in your development environment.
- On your live environment you are experiencing styling issues (styles not being applied).
- You have verified that the elements have the correct classes applied, and that the classes are in the Webpack compiled stylesheet.
- Despite this, in your inspector you can see that the classes are simply not being applied to the elements.
- You have noticed that some OTHER elements on your page are also not having their styles applied now.
This is a particularly pernicious little issue, as it doesn't appear until the code has already been compiled by Webpack into a staging or production environment. The evidence leads you to believe that this is some kind of Webpack issue at first, but we can inspect the compiled stylesheet and have verified that it is being loaded correctly and that the styles are in the sheet. WHAT IS HAPPENING!
The Culprit
In hindsight the issue is obvious. If you are like me, when you start working with a new Radix component like this Switch you probably copy the sample CSS from their example as a boilerplate to jump start your own styling, and place it in it's own CSS file. In this case the sample CSS is this:
@import '@radix-ui/colors/black-alpha.css';
/* reset */
button {
all: unset;
}
.SwitchRoot {
width: 42px;
height: 25px;
background-color: var(--black-a9);
border-radius: 9999px;
position: relative;
box-shadow: 0 2px 10px var(--black-a7);
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
&:focus {
box-shadow: 0 0 0 2px black;
}
&[data-state='checked'] {
background-color: black;
}
}
.SwitchThumb {
display: block;
width: 21px;
height: 21px;
background-color: white;
border-radius: 9999px;
box-shadow: 0 2px 2px var(--black-a7);
transition: transform 100ms;
transform: translateX(2px);
will-change: transform;
&[data-state='checked'] {
transform: translateX(19px);
}
}
.Label {
color: white;
font-size: 15px;
line-height: 1;
user-select: none;
}
and the highlighted section up top gives us the Culprit.
button {
all: unset;
}
Will remove all styles from all buttons. In the development environment this doesn't cause an issue as all the css files are treated as modules. However in the production environment the CSS is compiled by Webpack into one giant stylesheet. Whichever point in the stylesheet this class end up in, will remove any button styles previously defined to any button that comes after it. Ouch.
We do need to unset some previous styles for the Radix styling to work however. To resolve this issue we simply need to more specifically scope this class to just the Radix UI elements that we are targeting.
.radix-switchroot {
all: unset;
width: 28px;
height: 16px;
background-color: var(--bg-secondary);
border-radius: 9999px;
position: relative;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.radix-switchroot:focus {
box-shadow: 0 0 0 2px var(--text-secondary);
}
.radix-switchroot[data-state='checked'] {
background-color: var(--text-secondary);
}
._tag-cloud-control-row .radix-switchroot {
margin-left: auto;
}
.radix-switchroot .radix-switchthumb {
display: block;
width: 12px;
height: 12px;
background-color: var(--bg-primary);
border: 1px solid var(--text-primary);
border-radius: 9999px;
transition: transform 100ms;
transform: translateX(2px);
will-change: transform;
}
.radix-switchroot .radix-switchthumb[data-state='checked'] {
transform: translateX(14px);
}
This will leave the rest of your buttons in peace while still unsetting the styles on the radix element as intended.
Comments
Recent Work
Basalt
basalt.softwareFree desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.
BidBear
bidbear.ioBidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.