How to approach styling with Themes.
Themes does not come with a built-in styling system. There’s no css
or sx
prop, and it does not use any styling libraries internally. Under the hood, it’s built with vanilla CSS.
There’s no overhead when it comes to picking a styling technology for your app.
The components in Themes are relatively closed—they come with a set of styles that aren’t always easily overridden. They are customizable within what’s allowed by their props and the theme configuration.
However, you also get access to the same CSS variables that power the 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.
For more information on specific tokens, refer to the corresponding guides in the Theme section.
Beyond simple style overrides, we recommend using the components as-is, or create your own versions using the same building blocks.
Most components do have className
and style
props, but if you find yourself needing to override a lot of styles, it’s a good sign that you should either:
Tailwind is great. Yet, if you plan to use Themes with Tailwind, keep in mind how its ergonomics may encourage you to create complex styles on the fly, sometimes reaching into the component internals without friction.
Tailwind is a different styling paradigm, which may not mix well with the idea of a closed component system where customization is achieved through props, tokens, and creating new components on top of a shared set of building blocks.
If you need to create a custom component, use the same building blocks that Themes uses:
Feel free to explore the source code of Themes to see how it is built.
Out of the box, portalled Themes components can be nested and stacked in any order without conflicts. For example, you can open a popover that opens a dialog, which in turn opens another popover. They all stack on top of each other in the order they were opened:
When building your own components, use the following rules to avoid z-index conflicts:
z-index
values other than auto
, 0
, or -1
in rare cases.Your main content and portalled content are separated by the stacking context that the styles of the root <Theme>
component create. This allows you to stack portalled content on top of the main content without worrying about z-indices.
As of Next.js 13.0 to 14.1, the import order of CSS files in app/**/layout.tsx
is not guaranteed, so Themes may overwrite your own styles even when written correctly:
This Next.js issue may come and go sporadically, or happen only in development or production.
As a workaround, you can merge all the 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.
As of Tailwind v3, styles produced by the @tailwind
directive are usually appended after any imported CSS, no matter the original import order. In particular, Tailwind’s button reset style may interfere with Themes buttons, rendering certain buttons without a background color.
Workarounds:
@tailwind base
@import tailwindcss/base
before Themes styles.When you render a custom portal in a Themes project, it will naturally appear outside of the root <Theme>
component, which means it won’t have access to most of the theme tokens and styles. To fix that, wrap the portal content with another <Theme>
:
Components like Dialog and Popover in Themes already handle this for you, so this is only necessary when creating your own portalled components.
Usually, you’d want your custom CSS to override Themes styles. However, there are cases when it is natural to expect the opposite.
Consider a simple paragraph style that just resets the browser’s default margin:
You might apply the margin prop from a Box
onto your custom paragraph via asChild
:
Yet, this won’t work intuitively. The custom styles are imported after Themes styles, so they will override the margin prop. As a workaround, 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. However, if you use Next.js, keep in mind the import order issue that’s mentioned above.
If you use standalone layout components, split CSS files are also available for them: