JavaScript animation libraries require forceMount
When using JavaScript animation libraries like React Spring with Radix Primitives, you must use the forceMount prop to prevent the component from being removed from the React Tree during unmount, allowing the animation library to control the timing of the unmount phase.
forceMount prop for JavaScript animation libraries
Many stateful Radix Primitives provide a forceMount prop that allows delegating the mounting and unmounting of children based on animation state determined by JavaScript animation libraries. This is necessary because stateful Primitives normally remove their elements from the React Tree and DOM when hidden. The forceMount prop allows consumers to keep elements in the tree and control their visibility through the animation library.
React Spring animation example with Dialog
Example of animating a Dialog with React Spring using forceMount: Use Dialog.Root with open state, Dialog.Trigger to open. Use useTransition from react-spring to create transitions with from, enter, and leave states. Conditionally render Dialog.Overlay and Dialog.Content with forceMount and asChild props, wrapping them with animated.div from react-spring to apply the animation styles. The transitions function receives styles and item, rendering the content when item is truthy and applying opacity and transform styles from the animation state.
CSS fadeIn and fadeOut example for Dialog
CSS animation example for Dialog component: Define @keyframes fadeIn that animates opacity from 0 to 1, and @keyframes fadeOut that animates opacity from 1 to 0. Apply fadeIn animation (300ms ease-out) to .DialogOverlay[data-state="open"] and .DialogContent[data-state="open"]. Apply fadeOut animation (300ms ease-in) to .DialogOverlay[data-state="closed"] and .DialogContent[data-state="closed"].
CSS animation with data-state attributes
Radix Primitives can be animated using CSS animation targeting data-state attributes like [data-state="open"] and [data-state="closed"]. The Radix Primitives suspend unmount while your animation plays out, allowing CSS animations to control both mount and unmount phases.
Animation suspension for unmount phases
Radix Primitives suspend unmount while CSS animations play out, allowing the unmount phase to be animated with CSS. This behavior is built-in and does not require additional configuration.
Components ship unstyled for complete control
Components ship without styles, giving users complete control over the look and feel. Components can be styled with any styling solution.
Popper.Content inline animation style override fix
Fixed overriding inline animation style in Popper.Content.
animationend event with escapable characters
Ensured the animationend event is handled correctly when the keyframe has escapable characters.
Radix Themes 3.0.0 theme animations renamed with rt- prefix
Radix Themes 3.0.0 renamed all @keyframes animations with an `rt-` prefix and into kebab case.
Radix Themes 3.0.0 animation speedup
Radix Themes 3.0.0 sped up most animations throughout the library.
Radix Themes 3.0.0 breaking change: CSS color token renames
Radix Themes 3.0.0 renamed CSS color tokens: --color-surface-accent → --accent-surface. Contrast colors were renamed: --accent-9-contrast → --accent-contrast, --red-9-contrast → --red-contrast, --pink-9-contrast → --pink-contrast, --blue-9-contrast → --blue-contrast, and so on for all scales. Focus color tokens were added and old tokens renamed: --color-autofill-root → --focus-a3, --color-focus-root → --focus-8, --color-selection-root → --focus-a5. Tokens --gray-2-translucent and corresponding tinted gray colors were removed; use --color-panel-translucent with a backdrop blur filter instead.
Custom portals in Radix Themes lose theme tokens and styles
When you render a custom portal in a Radix Themes project, it will appear outside of the root Theme component and will not have access to most of the theme tokens and styles. To fix this, wrap the portal content with another Theme component.
Example: wrapping custom dialog portal with Theme component
import { Dialog } from 'radix-ui';
import { Theme } from '@radix-ui/themes';
function MyCustomDialog() {
return (
<Dialog.Root>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Portal>
<Theme>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title />
<Dialog.Description />
<Dialog.Close />
</Dialog.Content>
</Theme>
</Dialog.Portal>
</Dialog.Root>
);
}
This example shows how to wrap the portal content of a custom dialog using the low-level Dialog primitive with a Theme component to preserve access to theme tokens and styles.
Complex CSS precedence: split CSS files for Radix Themes
Radix Themes provides separate tokens.css, components.css, and utilities.css files that the original styles.css is built upon. You can import utilities.css after your custom styles to ensure that the layout props work as expected with your custom styles.
Example: importing split Radix Themes CSS files
import '@radix-ui/themes/tokens.css';
import '@radix-ui/themes/components.css';
import '@radix-ui/themes/utilities.css';
This shows how to import the separate CSS files from Radix Themes to have better control over CSS precedence.
Standalone layout components CSS files in Radix Themes
If you use standalone layout components in Radix Themes, split CSS files are also available for them: tokens.css, components.css, and utilities.css in the layout directory.
Example: importing split Radix Themes layout CSS files
import '@radix-ui/themes/layout/tokens.css';
import '@radix-ui/themes/layout/components.css';
import '@radix-ui/themes/layout/utilities.css';
This shows how to import the separate CSS files for standalone layout components in Radix Themes.
Radix Themes built with vanilla CSS, no styling library
Radix Themes does not come with a built-in styling system. There is no css or sx prop, and it does not use any styling libraries internally. It is built with vanilla CSS.
Radix Themes components are closed, customizable via props and theme configuration
The components in Radix Themes are relatively closed and come with a set of styles that are not always easily overridden. They are customizable within what is allowed by their props and the theme configuration.
Access to CSS variables from Radix Themes for custom components
You have access to the same CSS variables that power the Radix Themes components. You can use these tokens to create custom components that naturally feel at home in the original theme. Changes to the token system are treated as breaking.
Most Radix Themes components support className and style props
Most components in Radix Themes have className and style props available for styling. However, if you find yourself needing to override a lot of styles, it is recommended to use the components as-is, create your own versions using the same building blocks, or reconsider whether Radix Themes is the right fit.
Building blocks for custom Radix Themes components
When creating a custom component to use with Radix Themes, use the same building blocks that Radix Themes uses: Theme tokens that power the components, Radix Primitives (a library of accessible, unstyled components), and Radix Colors (a color system for building beautiful websites and apps).
Portalled Radix Themes components stack without z-index conflicts
Out of the box, portalled Radix Themes components can be nested and stacked in any order without conflicts. For example, you can open a popover that opens a dialog, which opens another popover, and they all stack on top of each other in the order they were opened.
Z-index rules for custom Radix Themes components
When building custom components to avoid z-index conflicts, follow these rules: do not use z-index values other than auto, 0, or -1 in rare cases; render elements that should stack on top of each other in portals. Your main content and portalled content are separated by the stacking context that the styles of the root Theme component create.
Next.js 13.0 to 14.1 CSS import order issue with Radix Themes
As of Next.js 13.0 to 14.1, the import order of CSS files in app/**/layout.tsx is not guaranteed, so Radix Themes may overwrite your own styles even when written correctly. This issue may come and go sporadically, or happen only in development or production.
Next.js CSS import order workarounds for Radix Themes
To work around the Next.js CSS import order issue with Radix Themes, you can merge all CSS into a single file first via postcss-import and import just that into your layout. Alternatively, importing the styles directly in page.tsx files also works.
Tailwind button reset interferes with Radix Themes buttons
As of Tailwind v3, styles produced by the @tailwind directive are usually appended after any imported CSS. In particular, Tailwind's button reset style may interfere with Radix Themes buttons, rendering certain buttons without a background color.
Tailwind and Radix Themes compatibility workarounds
To resolve Tailwind base style conflicts with Radix Themes, you can: do not use @tailwind base; set up separate CSS layers for Tailwind and Radix Themes; set up postcss-import and manually import Tailwind base styles via @import tailwindcss/base before Radix Themes styles.