Styles
An app that uses Pluto has exactly one Tailwind build. The CSS entry of the app owns it. No Pluto layer registers a Tailwind entry of its own.
Why
If two Tailwind builds are in one page, they declare the same cascade layers. A utility from the later stylesheet overrides the same utility of the earlier one. The responsive layout of the admin then breaks.
The CSS entry
Start your CSS entry with these three imports. Add your own theme after them.
@import 'tailwindcss';
@import '@nuxt/ui';
@import '@plutocms/css';
@theme {
/* your site's tokens */
}
Register the file in nuxt.config.ts:
export default defineNuxtConfig({
css: ['~/assets/css/main.css']
})
@plutocms/css brings in the CSS of every Pluto layer, including the admin theme. Nuxt UI already scans the source of every layer.
@plutocms/css is not an npm package, and you do not install it. Core makes it: it is a Nuxt alias of a file that core writes for your app. So it works with every package manager.
The pluto-css module
The module pluto-css is part of core. It does these things:
- It finds the
pluto-layer.cssfile of every layer. - It writes
#build/pluto.css, which imports each layer file. The base layer comes first, so a higher layer wins.@plutocms/cssis an alias of this file, and@plutocms/css/siteis an alias of the site theme. - It reads your CSS entries. If none imports
tailwindcss, it writes a fallback entry and adds it. This keeps a layer repository that runs on its own styled. An app with its own entry gets no fallback file.
The module has one option, plutoCss.check. The default is true. Set it to false to turn the warnings off. The module prints nothing during nuxt prepare.
The build prints a pluto-css warning, once for each problem, when:
- A layer registers its own Tailwind build.
- More than one Tailwind build exists.
- No entry imports
@plutocms/css. - No entry imports
@nuxt/ui.
The module does not add a second build when your app forgets the import.
Rules for a layer
A layer can ship app/assets/css/pluto-layer.css.
- Never import
tailwindcssor@nuxt/uiin it. - Use only
@theme,@custom-variant,@utility, unlayered rules, and imports of plain CSS files next to it. - Add no
@sourcefor theapp/directory of the layer. - Register no
cssentry in thenuxt.configof the layer.
Check the build
In the browser console, count the Tailwind builds:
[...document.querySelectorAll('style[data-vite-dev-id]')].filter(s => s.textContent.includes('tailwindcss v4')).length
The result must be 1, on the admin and on the public site. The build log must have no pluto-css warning.
Editor setup
The Tailwind CSS IntelliSense extension for VS Code makes a project of each CSS file that it finds, and the generated files in .nuxt/ are CSS files too. If a generated file wins over your CSS entry, the editor does not know your @theme: your own colors show no color swatch, and your own classes show no hover.
Tell the extension to ignore the generated files. Add this to .vscode/settings.json:
{
"files.associations": {
"*.css": "tailwindcss"
},
"tailwindCSS.files.exclude": [
"**/.git/**",
"**/node_modules/**",
"**/.hg/**",
"**/.svn/**",
"**/.nuxt/**",
"**/.output/**"
]
}
The first four patterns are the defaults of the extension. The setting replaces them, so keep them in the list. Then reload the editor window.
text-muted or bg-default, show no swatch. Their values are CSS variables that change with the color mode and with app.config, so the extension cannot show one color. Hover shows their CSS.The Pluto UI tokens
Core has the official palette and fonts of Pluto. Every app gets them as Tailwind tokens, so you can use them in your site:
| Token | Use |
|---|---|
tholin-50 to tholin-950 | The red-orange of Pluto's surface. The action color. |
haze-50 to haze-950 | The blue of Pluto's atmosphere. |
heart-50 to heart-950 | The tan and cream of the planet's heart. |
kuiper-50 to kuiper-950 | A cool, deep neutral for text, borders, and dark surfaces. |
font-pluto | Public Sans. |
font-pluto-display | Fredoka, the rounded face of the wordmark. |
<span class="bg-tholin-600 font-pluto-display text-white">Launch</span>
The tokens add new names only. They do not change the colors or the fonts of your site. To use the Pluto colors for Nuxt UI, set them in app.config: ui: { colors: { primary: 'tholin', neutral: 'kuiper' } }.
The Pluto site theme
To give your site the look of these docs, import the site theme after the core CSS:
@import 'tailwindcss';
@import '@nuxt/ui';
@import '@plutocms/css';
@import '@plutocms/css/site';
And set the Pluto colors in app.config:
export default defineAppConfig({
ui: {
colors: { primary: 'tholin', secondary: 'haze', neutral: 'kuiper' },
},
})
The site theme gives:
- Public Sans for text, and Fredoka for the page titles (
h1) and thefont-displayutility. - The shades of your colors that read well: primary 600 in light mode, primary 400 in dark mode.
- A dark mode of deep space (neutral 950).
- The
heartcolor for selected text. pluto-sky: a soft sky for the top of a page.pluto-site-header: put it on a sticky header, and the header moves below the admin bar while a signed-in editor sees the bar.
The theme does not choose your colors, so it works with your own palette too. It does not change the admin. The official templates use it.
The admin theme
The admin has its own look, made from the Pluto UI tokens. Your app.config colors and @theme tokens do not change it. To give the admin your brand, see White label.
| Role | Color |
|---|---|
| primary | tholin |
| secondary | haze |
| success | green |
| info | haze |
| warning | amber |
| error | rose |
| neutral | kuiper |
Errors use rose, not red, so an error does not look like the red-orange primary. The admin text font is Public Sans. Page titles use Fredoka. The admin radius is 0.25rem.
The theme applies under two selectors:
:root[data-pluto-admin]. The composableusePlutoAdminTheme()setsdata-pluto-adminon<html>while an admin layout is mounted. Overlays such as modals and menus also get the theme.[data-pluto-admin-scope]. It is for admin chrome that shows on the public site, such as the navbar of a signed-in admin.
Every value is a literal OKLCH color, so an app cannot redefine it.
Surfaces
In dark mode, the surfaces go from the darkest at the top to the lightest in the content: navbar, sidebar, canvas, cards. The navbar is near black in both modes.
The admin bar height
The token --pluto-admin-bar-height is 2.5rem on :root. A public site can use it to offset its own header under the admin bar. PlutoRoot sets data-pluto-admin-bar on <html> while the bar shows. See Admin shell.
Rules for admin code
- Use Nuxt UI semantic classes such as
bg-default,text-muted, andborder-default. Do not use raw Tailwind colors such asbg-zinc-100orbg-tholin-600. Raw colors do not follow the admin theme. - Call
usePlutoAdminTheme()in every new admin layout. - Put
data-pluto-admin-scopeon admin chrome that renders outside an admin layout. - Never put the admin radius in
@theme. It would reach the public site.
app.config, such as ui.button.slots.base, still merge across layers and reach the admin. Only colors, tokens, surfaces, and the font are isolated.