Write a theme

How to take a site from stock to styled.

Where your files go

Put your custom CSS and JavaScript here:

my-site/
├── .moss/
│   └── theme/
│       ├── style.css
│       └── script.js
├── index.md
└── ...

moss serves .moss/theme/ verbatim to /_moss/theme/ in the built site. Both files load automatically on every page. No build step, no config entry.

How your CSS wins

moss loads .moss/theme/style.css into the last CSS layer (@layer themes). It wins over all of moss's built-in styles by layer order. No !important needed. No @layer needed.

The three styling rungs

Work at the level that matches what you're changing.

Token override

Change a CSS custom property and every component that uses it follows:

:root {
  --moss-color-accent: #2d5a2d;
  --moss-font-body: "Inter", -apple-system, sans-serif;
  --moss-content-width: 72ch;
}

Use this rung for colors, fonts, spacing, and width — anything that should be consistent across the whole site.

CSS selector on semantic HTML

Target moss's stable class names for component-level changes. moss emits .moss-collection-card, .moss-article-listing, .moss-colophon, and many others. Target them directly:

.moss-collection-card {
  border-radius: 0;
}

The full list is in Component classes.

Named-class fenced div

Attach a custom class to a shortcode block with {.class} syntax, then target the combination:

:::grid 3 {.profiles}
...
:::
.profiles .moss-grid-card {
  border-radius: 50%;
}

Use this rung for one-off layout variations on a single page.

Dark mode

moss sets data-theme on <html> before first paint. It reads localStorage["moss-theme"] and falls back to the OS prefers-color-scheme. One block in your stylesheet covers both the toggle and the system preference.

Do not write @media (prefers-color-scheme: dark). Write this instead, which applies whenever dark mode is active regardless of how the visitor arrived there:

:root[data-theme="dark"] {
  --moss-color-bg: #0f0f0f;
  --moss-color-accent: #6abf6a;
}

Quiet chrome

--moss-color-ui-accent controls nav links, buttons, and site controls. It defaults to var(--moss-color-accent), tying navigation color to your content accent. To make the chrome recede while content links keep the accent, set it to a neutral:

:root {
  --moss-color-ui-accent: var(--moss-color-text);
}

Self-hosted fonts

Drop .woff2 files in .moss/theme/fonts/ and reference them from style.css:

@font-face {
  font-family: "MyFont";
  src: url("fonts/myfont.woff2") format("woff2");
}

For JavaScript, moss sets window.mossTheme.base to the /_moss/theme/ URL before script.js runs. Resolve assets against it:

const url = new URL("asset.woff2", mossTheme.base);

Where to find every token and class

For the full set:

Published with moss