Build your site

Styles

The admin has its own CSS. Your site can use Tailwind, or not.

The admin of Pluto has its own CSS. Core compiles it when your app builds. Your site does not need Tailwind, and your site's theme does not change the admin.

Two builds

An app that uses Pluto has at most two Tailwind builds:

  • The admin build. Core makes it. It styles the admin pages, the admin bar, and their menus and modals. Its rules apply only inside the admin, so they do not change your site. It loads only when the admin or the admin bar shows: a visitor does not download it.
  • The site build. Your CSS entry, if your site uses Tailwind. Core does not add one for you.

No Pluto layer registers a Tailwind entry of its own.

A site with Tailwind

If your pages use Tailwind or Nuxt UI, start your CSS entry with these imports. Add your own theme after them.

app/assets/css/main.css
@import 'tailwindcss';
@import '@nuxt/ui';
@import '@plutocms/css';
@import '@plutocms/css/base';

@theme {
  /* your site's tokens */
}

Register the file in nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/css/main.css']
})
  • @nuxt/ui is for the Nuxt UI components on your pages.
  • @plutocms/css gives your site the Pluto UI tokens and the tokens of your Pluto layers. It is optional.
  • @plutocms/css/base gives the look of the Pluto components for your public site. It is optional.

@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.

A site with no Tailwind

Write your CSS as you like. Pluto adds no Tailwind, no reset, and no utilities to your pages. The admin and the admin bar keep their look.

The Pluto components for public pages have no Tailwind classes, so they work on your site. For their look, import the base CSS in a CSS entry. It is plain CSS:

app/assets/css/main.css
@import '@plutocms/css/base';

The pluto-css module

The module pluto-css is part of core. It does these things:

  1. It finds the pluto-layer.css file of every layer.
  2. It writes #build/pluto.css, which imports each layer file. The base layer comes first, so a higher layer wins. @plutocms/css is an alias of this file, and @plutocms/css/site is an alias of the site theme.
  3. It writes the base CSS of the public components: one import of the pluto-base.css file of each layer. @plutocms/css/base is an alias of this file.
  4. It makes the admin build: Tailwind, Nuxt UI, @plutocms/css, and @plutocms/css/base, with every rule limited to the admin.
  5. It reads your CSS entries and warns about problems.

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.
  • Your app has more than one Tailwind build.

Rules for a layer

A layer can ship app/assets/css/pluto-layer.css. The admin build and the site build of a Tailwind site both import it, through @plutocms/css.

  • Never import tailwindcss or @nuxt/ui in it.
  • Use only @theme, @custom-variant, @utility, unlayered rules, and imports of plain CSS files next to it.
  • Add no @source for the app/ directory of the layer.
  • Register no css entry in the nuxt.config of the layer.

A layer with components for public pages can also ship app/assets/css/pluto-base.css, for their look. Use plain CSS only, with no Tailwind directive. Put each selector in :where() and each rule in @layer components, so the CSS of the site wins.

Check the build

  • Open a public page as a visitor. In the network panel of the browser, no file with a name that starts with PlutoAdminTheme loads.
  • Open the admin. It keeps its look, also when your @theme changes the spacing, the fonts, or the radius.
  • The build log has 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:

.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.

The semantic colors of Nuxt UI, such as 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. A Tailwind site gets them as Tailwind tokens through @plutocms/css, so you can use them in your site:

TokenUse
tholin-50 to tholin-950The red-orange of Pluto's surface. The action color.
haze-50 to haze-950The blue of Pluto's atmosphere.
heart-50 to heart-950The tan and cream of the planet's heart.
kuiper-50 to kuiper-950A cool, deep neutral for text, borders, and dark surfaces.
font-plutoPublic Sans.
font-pluto-displayFredoka, 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:

app/assets/css/main.css
@import 'tailwindcss';
@import '@nuxt/ui';
@import '@plutocms/css';
@import '@plutocms/css/site';

And set the Pluto colors in app.config:

app/app.config.ts
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 the font-display utility.
  • 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 heart color 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 shop template uses 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.

RoleColor
primarytholin
secondaryhaze
successgreen
infohaze
warningamber
errorrose
neutralkuiper

Errors use rose, not red, so an error does not look like the red-orange primary. The admin uses one font, Public Sans. Page titles are semibold. Fredoka is for the site only. The admin radius is 0.25rem.

The theme applies under two selectors:

  • :root[data-pluto-admin]. The composable usePlutoAdminTheme() sets data-pluto-admin on <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 navbar and the sidebar have no border between them and the page. They read as one shape, and the page has a rounded corner where they meet.

The admin bar height

The token --pluto-admin-bar-height is 2.5rem on :root, also on a site with no Tailwind. While the bar shows on a public page, PlutoRoot moves the page down by this height. A public site can use it to offset its own sticky or fixed 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, and border-default. Do not use raw Tailwind colors such as bg-zinc-100 or bg-tholin-600. Raw colors do not follow the admin theme.
  • Call usePlutoAdminTheme() in every new admin layout.
  • Put data-pluto-admin-scope on admin chrome that renders outside an admin layout.
  • Never put the admin radius in @theme. It would reach the public site.
Component themes in 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.